All Files (36.63% covered at 4.42 hits/line)
198 files in total.
14646 relevant lines.
5365 lines covered and
9281 lines missed
-
1
class ApplicationController < ActionController::Base
-
# Prevent CSRF attacks by raising an exception.
-
# For APIs, you may want to use :null_session instead.
-
1
protect_from_forgery with: :exception
-
end
-
1
class EventStepsController < ApplicationController
-
1
include Wicked::Wizard
-
1
steps :planner, :detail, :date, :place, :mail
-
1
before_action :set_event, only: [:show, :update]
-
-
1
def show
-
render_wizard
-
end
-
-
1
def update
-
if params[:add].present?
-
@event.update_attributes(event_params)
-
@event.schedule_dates.build if step == :date
-
@event.schedule_places.build if step == :place
-
render step
-
elsif step == steps.last
-
# SendMail.invitation(@event.id, params[:mail_address]).deliver if params[:send].present?
-
redirect_to event_url(@event), notice: "登録しました。"
-
else
-
@event.update_attributes(event_params)
-
render_wizard @event
-
end
-
end
-
-
1
private
-
# Use callbacks to share common setup or constraints between actions.
-
1
def set_event
-
@event = Event.find(params[:event_id])
-
end
-
-
# Never trust parameters from the scary internet, only allow the white list through.
-
1
def event_params
-
# params[:event]
-
params.require(:event).permit(:name, :detail, :planner, :password, :close_date, {schedule_dates_attributes: [:id, :date]}, {schedule_places_attributes: [:id, :name, :address, :price]})
-
end
-
end
-
1
class EventsController < ApplicationController
-
1
before_action :set_event, only: [:show, :edit, :destroy, :bulk_create]
-
-
# GET /events/1
-
# GET /events/1.json
-
1
def show
-
end
-
-
# GET /events/new
-
1
def new
-
1
@event = Event.new
-
1
if @event.save
-
1
redirect_to event_event_steps_url(@event)
-
else
-
redirect_to top_index_url
-
end
-
end
-
-
# GET /events/1/edit
-
1
def edit
-
1
redirect_to event_event_steps_url(@event)
-
end
-
-
# DELETE /events/1
-
# DELETE /events/1.json
-
1
def destroy
-
2
@event.destroy
-
2
respond_to do |format|
-
4
format.html { redirect_to top_index_url }
-
2
format.json { head :no_content }
-
end
-
end
-
-
1
def bulk_create
-
3
@board = @event.boards.build(board_params)
-
-
3
respond_to do |format|
-
3
if @board.save
-
6
format.html { redirect_to @event, notice: '投稿しました。'}
-
3
format.json { render action: 'show', status: :created, location: @board }
-
else
-
format.html { render action: 'show' }
-
format.json { render json: @board.errors, status: :unprocessable_entity }
-
end
-
end
-
end
-
-
1
private
-
# Use callbacks to share common setup or constraints between actions.
-
1
def set_event
-
7
@event = Event.find(params[:id])
-
end
-
-
# Never trust parameters from the scary internet, only allow the white list through.
-
1
def event_params
-
# params[:event]
-
params.require(:event).permit(:name, :detail, :planner, :password, :close_date)
-
end
-
-
# Never trust parameters from the scary internet, only allow the white list through.
-
1
def board_params
-
3
params.require(:board).permit(:name, :tweet)
-
end
-
end
-
1
class MemberStepsController < ApplicationController
-
1
include Wicked::Wizard
-
1
steps :member, :date, :place
-
1
before_action :set_event, only: [:show, :update]
-
1
before_action :set_member, only: [:show, :update]
-
-
1
def show
-
render_wizard
-
end
-
-
1
def update
-
if params[:add].present?
-
# @event.update_attributes(event_params)
-
# @event.schedule_dates.build if step == :date
-
# @event.schedule_places.build if step == :place
-
# render step
-
elsif step == steps.last
-
# SendMail.invitation(@event.id, params[:mail_address]).deliver if params[:send].present?
-
redirect_to event_url(@event), notice: "登録しました。"
-
else
-
@member.update_attributes(member_params)
-
render_wizard @member
-
end
-
end
-
-
1
private
-
# Use callbacks to share common setup or constraints between actions.
-
1
def set_event
-
@event = Event.find(params[:event_id])
-
end
-
-
1
def set_member
-
@member = Member.find(params[:member_id])
-
end
-
-
# Never trust parameters from the scary internet, only allow the white list through.
-
1
def member_params
-
# params[:member]
-
params.require(:member).permit(:name, :password, {hope_dates_attributes: [:id, :schedule_date_id]}, {hope_places_attributes: [:id, :schedule_place_id]})
-
end
-
end
-
1
class MembersController < ApplicationController
-
1
before_action :set_event, only: [:new, :edit, :destroy]
-
1
before_action :set_member, only: [:edit, :destroy]
-
-
# GET /members/new
-
1
def new
-
1
@member = @event.members.build
-
1
if @member.save
-
1
redirect_to event_member_member_steps_url(@event, @member)
-
else
-
redirect_to event_path_url(@event)
-
end
-
end
-
-
# GET /members/1/edit
-
1
def edit
-
1
redirect_to event_member_member_steps_url(@event, @member)
-
end
-
-
# DELETE /members/1
-
# DELETE /members/1.json
-
1
def destroy
-
2
@member.destroy
-
2
respond_to do |format|
-
4
format.html { redirect_to Event.find(params[:event_id])}
-
2
format.json { head :no_content }
-
end
-
end
-
-
1
private
-
# use callbacks to share common setup or constraints between actions.
-
1
def set_event
-
4
@event = Event.find(params[:event_id])
-
end
-
-
# use callbacks to share common setup or constraints between actions.
-
1
def set_member
-
3
@member = Member.find(params[:id])
-
end
-
-
# Never trust parameters from the scary internet, only allow the white list through.
-
1
def member_params
-
params[:member]
-
end
-
end
-
1
class TopController < ApplicationController
-
end
-
1
class SendMail < ActionMailer::Base
-
1
default from: "from@example.com"
-
# default from: "bounenkai.rb@gmail.com"
-
-
# Subject can be set in your I18n file at config/locales/en.yml
-
# with the following lookup:
-
#
-
# en.send_mail.invitation.subject
-
#
-
1
def invitation
-
# def invitation(event_id, address)
-
2
@greeting = "Hi"
-
-
2
mail to: "to@example.org"
-
# mail to: address
-
end
-
end
-
1
class Board < ActiveRecord::Base
-
1
acts_as_paranoid
-
-
1
validates :name,
-
:tweet,
-
presence: true
-
end
-
1
class Event < ActiveRecord::Base
-
1
acts_as_paranoid
-
-
1
has_many :members, dependent: :destroy
-
1
has_many :boards, dependent: :destroy
-
1
has_many :schedule_dates, dependent: :destroy
-
1
has_many :schedule_places, dependent: :destroy
-
-
1
accepts_nested_attributes_for :schedule_dates
-
1
accepts_nested_attributes_for :schedule_places
-
end
-
1
class HopeDate < ActiveRecord::Base
-
1
acts_as_paranoid
-
end
-
1
class HopePlace < ActiveRecord::Base
-
1
acts_as_paranoid
-
end
-
1
class Member < ActiveRecord::Base
-
1
acts_as_paranoid
-
end
-
1
class ScheduleDate < ActiveRecord::Base
-
1
acts_as_paranoid
-
-
1
validates :date,
-
presence: true
-
end
-
1
class SchedulePlace < ActiveRecord::Base
-
1
acts_as_paranoid
-
-
1
validates :name,
-
:address,
-
:price,
-
presence: true
-
end
-
1
require 'spec_helper'
-
-
# This spec was generated by rspec-rails when you ran the scaffold generator.
-
# It demonstrates how one might use RSpec to specify the controller code that
-
# was generated by Rails when you ran the scaffold generator.
-
#
-
# It assumes that the implementation code is generated by the rails scaffold
-
# generator. If you are using any extension libraries to generate different
-
# controller code, this generated spec may or may not pass.
-
#
-
# It only uses APIs available in rails and/or rspec-rails. There are a number
-
# of tools you can use to make these specs even more expressive, but we're
-
# sticking to rails and rspec-rails APIs to keep things simple and stable.
-
#
-
# Compared to earlier versions of this generator, there is very limited use of
-
# stubs and message expectations in this spec. Stubs are only used when there
-
# is no simpler way to get a handle on the object needed for the example.
-
# Message expectations are only used when there is no simpler way to specify
-
# that an instance is receiving a specific message.
-
-
1
describe EventsController do
-
-
# This should return the minimal set of attributes required to create a valid
-
# Event. As you add validations to Event, be sure to
-
# adjust the attributes here as well.
-
8
let(:valid_attributes) { { name: 'test_name', detail: 'test_detail', password: '0000' } }
-
4
let(:board_valid_attributes) { { name: 'test_name', tweet: 'test_tweet' } }
-
-
# This should return the minimal set of values that should be in the session
-
# in order to pass any filters (e.g. authentication) defined in
-
# EventsController. Be sure to keep this updated too.
-
9
let(:valid_session) { {} }
-
-
1
describe "GET show" do
-
1
it "assigns the requested event as @event" do
-
1
event = Event.create! valid_attributes
-
1
get :show, {:id => event.to_param}, valid_session
-
1
assigns(:event).should eq(event)
-
end
-
end
-
-
1
describe "GET new" do
-
1
it "assigns a new event as @event" do
-
1
get :new, {}, valid_session
-
# assigns(:event).should be_a_new(Event)
-
1
response.should redirect_to(event_event_steps_url(Event.last))
-
end
-
end
-
-
1
describe "GET edit" do
-
1
it "assigns the requested event as @event" do
-
1
event = Event.create! valid_attributes
-
1
get :edit, {:id => event.to_param}, valid_session
-
1
assigns(:event).should eq(event)
-
end
-
end
-
-
1
describe "DELETE destroy" do
-
1
it "destroys the requested event" do
-
1
event = Event.create! valid_attributes
-
1
expect {
-
1
delete :destroy, {:id => event.to_param}, valid_session
-
}.to change(Event, :count).by(-1)
-
end
-
-
1
it "redirects to the events list" do
-
1
event = Event.create! valid_attributes
-
1
delete :destroy, {:id => event.to_param}, valid_session
-
1
response.should redirect_to(top_index_url)
-
end
-
end
-
-
1
describe "POST bulk_create" do
-
1
describe "with valid params" do
-
1
it "creates a new Board" do
-
1
event = Event.create! valid_attributes
-
1
expect {
-
1
post :bulk_create, {:id => event.to_param, :board => board_valid_attributes}, valid_session
-
}.to change(Board, :count).by(1)
-
end
-
-
1
it "assigns a newly created board as @board" do
-
1
event = Event.create! valid_attributes
-
1
post :bulk_create, {:id => event.to_param, :board => board_valid_attributes}, valid_session
-
1
assigns(:board).should be_a(Board)
-
1
assigns(:board).should be_persisted
-
end
-
-
1
it "redirects to the created board" do
-
1
event = Event.create! valid_attributes
-
1
post :bulk_create, {:id => event.to_param, :board => board_valid_attributes}, valid_session
-
1
response.should redirect_to(Event.last)
-
end
-
end
-
-
# describe "with invalid params" do
-
# it "assigns a newly created but unsaved board as @board" do
-
# event = Event.create! valid_attributes
-
# # Trigger the behavior that occurs when invalid params are submitted
-
# Board.any_instance.stub(:save).and_return(false)
-
# post :bulk_create, {:id => event.to_param, :board => { password: 'invalid' }}, valid_session
-
# assigns(:board).should be_a_new(Board)
-
# end
-
-
# it "re-renders the 'new' template" do
-
# event = Event.create! valid_attributes
-
# # Trigger the behavior that occurs when invalid params are submitted
-
# Board.any_instance.stub(:save).and_return(false)
-
# post :bulk_create, {:id => event.to_param, :board => { password: 'invalid' }}, valid_session
-
# response.should render_template("new")
-
# end
-
# end
-
end
-
end
-
1
require 'spec_helper'
-
-
1
describe MemberStepsController do
-
-
end
-
1
require 'spec_helper'
-
-
# This spec was generated by rspec-rails when you ran the scaffold generator.
-
# It demonstrates how one might use RSpec to specify the controller code that
-
# was generated by Rails when you ran the scaffold generator.
-
#
-
# It assumes that the implementation code is generated by the rails scaffold
-
# generator. If you are using any extension libraries to generate different
-
# controller code, this generated spec may or may not pass.
-
#
-
# It only uses APIs available in rails and/or rspec-rails. There are a number
-
# of tools you can use to make these specs even more expressive, but we're
-
# sticking to rails and rspec-rails APIs to keep things simple and stable.
-
#
-
# Compared to earlier versions of this generator, there is very limited use of
-
# stubs and message expectations in this spec. Stubs are only used when there
-
# is no simpler way to get a handle on the object needed for the example.
-
# Message expectations are only used when there is no simpler way to specify
-
# that an instance is receiving a specific message.
-
-
1
describe MembersController do
-
1
before(:each) do
-
4
@event = create(:event)
-
end
-
-
# This should return the minimal set of attributes required to create a valid
-
# Member. As you add validations to Member, be sure to
-
# adjust the attributes here as well.
-
4
let(:valid_attributes) { { } }
-
-
# This should return the minimal set of values that should be in the session
-
# in order to pass any filters (e.g. authentication) defined in
-
# MembersController. Be sure to keep this updated too.
-
5
let(:valid_session) { {} }
-
-
1
describe "GET new" do
-
1
it "assigns a new member as @member" do
-
1
get :new, {:event_id => @event.id}, valid_session
-
# assigns(:member).should be_a_new(Member)
-
1
response.should redirect_to(event_member_member_steps_url(@event, Member.last))
-
end
-
end
-
-
1
describe "GET edit" do
-
1
it "assigns the requested member as @member" do
-
1
member = Member.create! valid_attributes
-
1
get :edit, {:id => member.to_param, :event_id => @event.id}, valid_session
-
1
assigns(:member).should eq(member)
-
end
-
end
-
-
1
describe "DELETE destroy" do
-
1
it "destroys the requested member" do
-
1
member = Member.create! valid_attributes
-
1
expect {
-
1
delete :destroy, {:id => member.to_param, :event_id => @event.id}, valid_session
-
}.to change(Member, :count).by(-1)
-
end
-
-
1
it "redirects to the members list" do
-
1
member = Member.create! valid_attributes
-
1
delete :destroy, {:id => member.to_param, :event_id => @event.id}, valid_session
-
# response.should redirect_to(members_url)
-
1
response.should redirect_to(Event.find(@event.id))
-
end
-
end
-
-
end
-
1
require 'spec_helper'
-
-
1
describe TopController do
-
-
end
-
1
require 'spec_helper'
-
-
# Specs in this file have access to a helper object that includes
-
# the EventStepsHelper. For example:
-
#
-
# describe EventStepsHelper do
-
# describe "string concat" do
-
# it "concats two strings with spaces" do
-
# helper.concat_strings("this","that").should == "this that"
-
# end
-
# end
-
# end
-
1
describe EventStepsHelper do
-
1
pending "add some examples to (or delete) #{__FILE__}"
-
end
-
1
require 'spec_helper'
-
-
# Specs in this file have access to a helper object that includes
-
# the EventsHelper. For example:
-
#
-
# describe EventsHelper do
-
# describe "string concat" do
-
# it "concats two strings with spaces" do
-
# helper.concat_strings("this","that").should == "this that"
-
# end
-
# end
-
# end
-
1
describe EventsHelper do
-
1
pending "add some examples to (or delete) #{__FILE__}"
-
end
-
1
require 'spec_helper'
-
-
# Specs in this file have access to a helper object that includes
-
# the MemberStepsHelper. For example:
-
#
-
# describe MemberStepsHelper do
-
# describe "string concat" do
-
# it "concats two strings with spaces" do
-
# helper.concat_strings("this","that").should == "this that"
-
# end
-
# end
-
# end
-
1
describe MemberStepsHelper do
-
1
pending "add some examples to (or delete) #{__FILE__}"
-
end
-
1
require 'spec_helper'
-
-
# Specs in this file have access to a helper object that includes
-
# the MembersHelper. For example:
-
#
-
# describe MembersHelper do
-
# describe "string concat" do
-
# it "concats two strings with spaces" do
-
# helper.concat_strings("this","that").should == "this that"
-
# end
-
# end
-
# end
-
1
describe MembersHelper do
-
1
pending "add some examples to (or delete) #{__FILE__}"
-
end
-
1
require 'spec_helper'
-
-
# Specs in this file have access to a helper object that includes
-
# the TopHelper. For example:
-
#
-
# describe TopHelper do
-
# describe "string concat" do
-
# it "concats two strings with spaces" do
-
# helper.concat_strings("this","that").should == "this that"
-
# end
-
# end
-
# end
-
1
describe TopHelper do
-
1
pending "add some examples to (or delete) #{__FILE__}"
-
end
-
1
require "spec_helper"
-
-
1
describe SendMail do
-
1
describe "invitation" do
-
3
let(:mail) { SendMail.invitation }
-
-
1
it "renders the headers" do
-
1
mail.subject.should eq("Invitation")
-
1
mail.to.should eq(["to@example.org"])
-
1
mail.from.should eq(["from@example.com"])
-
end
-
-
1
it "renders the body" do
-
1
mail.body.encoded.should match("Hi")
-
end
-
end
-
-
end
-
1
require 'spec_helper'
-
-
1
describe Board do
-
2
it{ should validate_presence_of(:name) }
-
2
it{ should validate_presence_of(:tweet) }
-
end
-
1
require 'spec_helper'
-
-
1
describe Event do
-
end
-
1
require 'spec_helper'
-
-
1
describe HopeDate do
-
end
-
1
require 'spec_helper'
-
-
1
describe HopePlace do
-
end
-
1
require 'spec_helper'
-
-
1
describe Member do
-
end
-
1
require 'spec_helper'
-
-
1
describe ScheduleDate do
-
2
it{ should validate_presence_of(:date) }
-
end
-
1
require 'spec_helper'
-
-
1
describe SchedulePlace do
-
2
it{ should validate_presence_of(:name) }
-
2
it{ should validate_presence_of(:address) }
-
end
-
1
require "spec_helper"
-
-
1
describe EventsController do
-
1
describe "routing" do
-
-
1
it "routes to #new" do
-
1
get("/events/new").should route_to("events#new")
-
end
-
-
1
it "routes to #show" do
-
1
get("/events/1").should route_to("events#show", :id => "1")
-
end
-
-
1
it "routes to #edit" do
-
1
get("/events/1/edit").should route_to("events#edit", :id => "1")
-
end
-
-
1
it "routes to #destroy" do
-
1
delete("/events/1").should route_to("events#destroy", :id => "1")
-
end
-
-
1
it "routes to #bulk_create" do
-
1
post("/events/1/bulk_create").should route_to("events#bulk_create", :id => "1")
-
end
-
end
-
end
-
1
require "spec_helper"
-
-
1
describe MembersController do
-
1
describe "routing" do
-
-
1
it "routes to #new" do
-
1
get("/events/1/members/new").should route_to("members#new", :event_id => "1")
-
end
-
-
1
it "routes to #edit" do
-
1
get("/events/1/members/1/edit").should route_to("members#edit", :event_id => "1", :id => "1")
-
end
-
-
1
it "routes to #destroy" do
-
1
delete("/events/1/members/1").should route_to("members#destroy", :event_id => "1", :id => "1")
-
end
-
-
end
-
end
-
1
require 'mail'
-
1
require 'action_mailer/collector'
-
1
require 'active_support/core_ext/string/inflections'
-
1
require 'active_support/core_ext/hash/except'
-
1
require 'active_support/core_ext/module/anonymous'
-
1
require 'action_mailer/log_subscriber'
-
-
1
module ActionMailer
-
# Action Mailer allows you to send email from your application using a mailer model and views.
-
#
-
# = Mailer Models
-
#
-
# To use Action Mailer, you need to create a mailer model.
-
#
-
# $ rails generate mailer Notifier
-
#
-
# The generated model inherits from <tt>ActionMailer::Base</tt>. A mailer model defines methods
-
# used to generate an email message. In these methods, you can setup variables to be used in
-
# the mailer views, options on the mail itself such as the <tt>:from</tt> address, and attachments.
-
#
-
# class Notifier < ActionMailer::Base
-
# default from: 'no-reply@example.com',
-
# return_path: 'system@example.com'
-
#
-
# def welcome(recipient)
-
# @account = recipient
-
# mail(to: recipient.email_address_with_name,
-
# bcc: ["bcc@example.com", "Order Watcher <watcher@example.com>"])
-
# end
-
# end
-
#
-
# Within the mailer method, you have access to the following methods:
-
#
-
# * <tt>attachments[]=</tt> - Allows you to add attachments to your email in an intuitive
-
# manner; <tt>attachments['filename.png'] = File.read('path/to/filename.png')</tt>
-
#
-
# * <tt>attachments.inline[]=</tt> - Allows you to add an inline attachment to your email
-
# in the same manner as <tt>attachments[]=</tt>
-
#
-
# * <tt>headers[]=</tt> - Allows you to specify any header field in your email such
-
# as <tt>headers['X-No-Spam'] = 'True'</tt>. Note, while most fields like <tt>To:</tt>
-
# <tt>From:</tt> can only appear once in an email header, other fields like <tt>X-Anything</tt>
-
# can appear multiple times. If you want to change a field that can appear multiple times,
-
# you need to set it to nil first so that Mail knows you are replacing it and not adding
-
# another field of the same name.
-
#
-
# * <tt>headers(hash)</tt> - Allows you to specify multiple headers in your email such
-
# as <tt>headers({'X-No-Spam' => 'True', 'In-Reply-To' => '1234@message.id'})</tt>
-
#
-
# * <tt>mail</tt> - Allows you to specify email to be sent.
-
#
-
# The hash passed to the mail method allows you to specify any header that a Mail::Message
-
# will accept (any valid Email header including optional fields).
-
#
-
# The mail method, if not passed a block, will inspect your views and send all the views with
-
# the same name as the method, so the above action would send the +welcome.text.erb+ view
-
# file as well as the +welcome.text.html.erb+ view file in a +multipart/alternative+ email.
-
#
-
# If you want to explicitly render only certain templates, pass a block:
-
#
-
# mail(to: user.email) do |format|
-
# format.text
-
# format.html
-
# end
-
#
-
# The block syntax is also useful in providing information specific to a part:
-
#
-
# mail(to: user.email) do |format|
-
# format.text(content_transfer_encoding: "base64")
-
# format.html
-
# end
-
#
-
# Or even to render a special view:
-
#
-
# mail(to: user.email) do |format|
-
# format.text
-
# format.html { render "some_other_template" }
-
# end
-
#
-
# = Mailer views
-
#
-
# Like Action Controller, each mailer class has a corresponding view directory in which each
-
# method of the class looks for a template with its name.
-
#
-
# To define a template to be used with a mailing, create an <tt>.erb</tt> file with the same
-
# name as the method in your mailer model. For example, in the mailer defined above, the template at
-
# <tt>app/views/notifier/welcome.text.erb</tt> would be used to generate the email.
-
#
-
# Variables defined in the model are accessible as instance variables in the view.
-
#
-
# Emails by default are sent in plain text, so a sample view for our model example might look like this:
-
#
-
# Hi <%= @account.name %>,
-
# Thanks for joining our service! Please check back often.
-
#
-
# You can even use Action Pack helpers in these views. For example:
-
#
-
# You got a new note!
-
# <%= truncate(@note.body, length: 25) %>
-
#
-
# If you need to access the subject, from or the recipients in the view, you can do that through message object:
-
#
-
# You got a new note from <%= message.from %>!
-
# <%= truncate(@note.body, length: 25) %>
-
#
-
#
-
# = Generating URLs
-
#
-
# URLs can be generated in mailer views using <tt>url_for</tt> or named routes. Unlike controllers from
-
# Action Pack, the mailer instance doesn't have any context about the incoming request, so you'll need
-
# to provide all of the details needed to generate a URL.
-
#
-
# When using <tt>url_for</tt> you'll need to provide the <tt>:host</tt>, <tt>:controller</tt>, and <tt>:action</tt>:
-
#
-
# <%= url_for(host: "example.com", controller: "welcome", action: "greeting") %>
-
#
-
# When using named routes you only need to supply the <tt>:host</tt>:
-
#
-
# <%= users_url(host: "example.com") %>
-
#
-
# You should use the <tt>named_route_url</tt> style (which generates absolute URLs) and avoid using the
-
# <tt>named_route_path</tt> style (which generates relative URLs), since clients reading the mail will
-
# have no concept of a current URL from which to determine a relative path.
-
#
-
# It is also possible to set a default host that will be used in all mailers by setting the <tt>:host</tt>
-
# option as a configuration option in <tt>config/application.rb</tt>:
-
#
-
# config.action_mailer.default_url_options = { host: "example.com" }
-
#
-
# When you decide to set a default <tt>:host</tt> for your mailers, then you need to make sure to use the
-
# <tt>only_path: false</tt> option when using <tt>url_for</tt>. Since the <tt>url_for</tt> view helper
-
# will generate relative URLs by default when a <tt>:host</tt> option isn't explicitly provided, passing
-
# <tt>only_path: false</tt> will ensure that absolute URLs are generated.
-
#
-
# = Sending mail
-
#
-
# Once a mailer action and template are defined, you can deliver your message or create it and save it
-
# for delivery later:
-
#
-
# Notifier.welcome(david).deliver # sends the email
-
# mail = Notifier.welcome(david) # => a Mail::Message object
-
# mail.deliver # sends the email
-
#
-
# You never instantiate your mailer class. Rather, you just call the method you defined on the class itself.
-
#
-
# = Multipart Emails
-
#
-
# Multipart messages can also be used implicitly because Action Mailer will automatically detect and use
-
# multipart templates, where each template is named after the name of the action, followed by the content
-
# type. Each such detected template will be added as a separate part to the message.
-
#
-
# For example, if the following templates exist:
-
# * signup_notification.text.erb
-
# * signup_notification.text.html.erb
-
# * signup_notification.text.xml.builder
-
# * signup_notification.text.yaml.erb
-
#
-
# Each would be rendered and added as a separate part to the message, with the corresponding content
-
# type. The content type for the entire message is automatically set to <tt>multipart/alternative</tt>,
-
# which indicates that the email contains multiple different representations of the same email
-
# body. The same instance variables defined in the action are passed to all email templates.
-
#
-
# Implicit template rendering is not performed if any attachments or parts have been added to the email.
-
# This means that you'll have to manually add each part to the email and set the content type of the email
-
# to <tt>multipart/alternative</tt>.
-
#
-
# = Attachments
-
#
-
# Sending attachment in emails is easy:
-
#
-
# class ApplicationMailer < ActionMailer::Base
-
# def welcome(recipient)
-
# attachments['free_book.pdf'] = File.read('path/to/file.pdf')
-
# mail(to: recipient, subject: "New account information")
-
# end
-
# end
-
#
-
# Which will (if it had both a <tt>welcome.text.erb</tt> and <tt>welcome.text.html.erb</tt>
-
# template in the view directory), send a complete <tt>multipart/mixed</tt> email with two parts,
-
# the first part being a <tt>multipart/alternative</tt> with the text and HTML email parts inside,
-
# and the second being a <tt>application/pdf</tt> with a Base64 encoded copy of the file.pdf book
-
# with the filename +free_book.pdf+.
-
#
-
# If you need to send attachments with no content, you need to create an empty view for it,
-
# or add an empty body parameter like this:
-
#
-
# class ApplicationMailer < ActionMailer::Base
-
# def welcome(recipient)
-
# attachments['free_book.pdf'] = File.read('path/to/file.pdf')
-
# mail(to: recipient, subject: "New account information", body: "")
-
# end
-
# end
-
#
-
# = Inline Attachments
-
#
-
# You can also specify that a file should be displayed inline with other HTML. This is useful
-
# if you want to display a corporate logo or a photo.
-
#
-
# class ApplicationMailer < ActionMailer::Base
-
# def welcome(recipient)
-
# attachments.inline['photo.png'] = File.read('path/to/photo.png')
-
# mail(to: recipient, subject: "Here is what we look like")
-
# end
-
# end
-
#
-
# And then to reference the image in the view, you create a <tt>welcome.html.erb</tt> file and
-
# make a call to +image_tag+ passing in the attachment you want to display and then call
-
# +url+ on the attachment to get the relative content id path for the image source:
-
#
-
# <h1>Please Don't Cringe</h1>
-
#
-
# <%= image_tag attachments['photo.png'].url -%>
-
#
-
# As we are using Action View's +image_tag+ method, you can pass in any other options you want:
-
#
-
# <h1>Please Don't Cringe</h1>
-
#
-
# <%= image_tag attachments['photo.png'].url, alt: 'Our Photo', class: 'photo' -%>
-
#
-
# = Observing and Intercepting Mails
-
#
-
# Action Mailer provides hooks into the Mail observer and interceptor methods. These allow you to
-
# register classes that are called during the mail delivery life cycle.
-
#
-
# An observer class must implement the <tt>:delivered_email(message)</tt> method which will be
-
# called once for every email sent after the email has been sent.
-
#
-
# An interceptor class must implement the <tt>:delivering_email(message)</tt> method which will be
-
# called before the email is sent, allowing you to make modifications to the email before it hits
-
# the delivery agents. Your class should make any needed modifications directly to the passed
-
# in Mail::Message instance.
-
#
-
# = Default Hash
-
#
-
# Action Mailer provides some intelligent defaults for your emails, these are usually specified in a
-
# default method inside the class definition:
-
#
-
# class Notifier < ActionMailer::Base
-
# default sender: 'system@example.com'
-
# end
-
#
-
# You can pass in any header value that a <tt>Mail::Message</tt> accepts. Out of the box,
-
# <tt>ActionMailer::Base</tt> sets the following:
-
#
-
# * <tt>mime_version: "1.0"</tt>
-
# * <tt>charset: "UTF-8",</tt>
-
# * <tt>content_type: "text/plain",</tt>
-
# * <tt>parts_order: [ "text/plain", "text/enriched", "text/html" ]</tt>
-
#
-
# <tt>parts_order</tt> and <tt>charset</tt> are not actually valid <tt>Mail::Message</tt> header fields,
-
# but Action Mailer translates them appropriately and sets the correct values.
-
#
-
# As you can pass in any header, you need to either quote the header as a string, or pass it in as
-
# an underscored symbol, so the following will work:
-
#
-
# class Notifier < ActionMailer::Base
-
# default 'Content-Transfer-Encoding' => '7bit',
-
# content_description: 'This is a description'
-
# end
-
#
-
# Finally, Action Mailer also supports passing <tt>Proc</tt> objects into the default hash, so you
-
# can define methods that evaluate as the message is being generated:
-
#
-
# class Notifier < ActionMailer::Base
-
# default 'X-Special-Header' => Proc.new { my_method }
-
#
-
# private
-
#
-
# def my_method
-
# 'some complex call'
-
# end
-
# end
-
#
-
# Note that the proc is evaluated right at the start of the mail message generation, so if you
-
# set something in the defaults using a proc, and then set the same thing inside of your
-
# mailer method, it will get over written by the mailer method.
-
#
-
# It is also possible to set these default options that will be used in all mailers through
-
# the <tt>default_options=</tt> configuration in <tt>config/application.rb</tt>:
-
#
-
# config.action_mailer.default_options = { from: "no-reply@example.org" }
-
#
-
# = Callbacks
-
#
-
# You can specify callbacks using before_action and after_action for configuring your messages.
-
# This may be useful, for example, when you want to add default inline attachments for all
-
# messages sent out by a certain mailer class:
-
#
-
# class Notifier < ActionMailer::Base
-
# before_action :add_inline_attachment!
-
#
-
# def welcome
-
# mail
-
# end
-
#
-
# private
-
#
-
# def add_inline_attachment!
-
# attachments.inline["footer.jpg"] = File.read('/path/to/filename.jpg')
-
# end
-
# end
-
#
-
# Callbacks in ActionMailer are implemented using AbstractController::Callbacks, so you
-
# can define and configure callbacks in the same manner that you would use callbacks in
-
# classes that inherit from ActionController::Base.
-
#
-
# Note that unless you have a specific reason to do so, you should prefer using before_action
-
# rather than after_action in your ActionMailer classes so that headers are parsed properly.
-
#
-
# = Configuration options
-
#
-
# These options are specified on the class level, like
-
# <tt>ActionMailer::Base.raise_delivery_errors = true</tt>
-
#
-
# * <tt>default_options</tt> - You can pass this in at a class level as well as within the class itself as
-
# per the above section.
-
#
-
# * <tt>logger</tt> - the logger is used for generating information on the mailing run if available.
-
# Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
-
#
-
# * <tt>smtp_settings</tt> - Allows detailed configuration for <tt>:smtp</tt> delivery method:
-
# * <tt>:address</tt> - Allows you to use a remote mail server. Just change it from its default
-
# "localhost" setting.
-
# * <tt>:port</tt> - On the off chance that your mail server doesn't run on port 25, you can change it.
-
# * <tt>:domain</tt> - If you need to specify a HELO domain, you can do it here.
-
# * <tt>:user_name</tt> - If your mail server requires authentication, set the username in this setting.
-
# * <tt>:password</tt> - If your mail server requires authentication, set the password in this setting.
-
# * <tt>:authentication</tt> - If your mail server requires authentication, you need to specify the
-
# authentication type here.
-
# This is a symbol and one of <tt>:plain</tt> (will send the password in the clear), <tt>:login</tt> (will
-
# send password Base64 encoded) or <tt>:cram_md5</tt> (combines a Challenge/Response mechanism to exchange
-
# information and a cryptographic Message Digest 5 algorithm to hash important information)
-
# * <tt>:enable_starttls_auto</tt> - When set to true, detects if STARTTLS is enabled in your SMTP server
-
# and starts to use it.
-
# * <tt>:openssl_verify_mode</tt> - When using TLS, you can set how OpenSSL checks the certificate. This is
-
# really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name
-
# of an OpenSSL verify constant ('none', 'peer', 'client_once', 'fail_if_no_peer_cert') or directly the
-
# constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER, ...).
-
#
-
# * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method.
-
# * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>.
-
# * <tt>:arguments</tt> - The command line arguments. Defaults to <tt>-i -t</tt> with <tt>-f sender@address</tt>
-
# added automatically before the message is sent.
-
#
-
# * <tt>file_settings</tt> - Allows you to override options for the <tt>:file</tt> delivery method.
-
# * <tt>:location</tt> - The directory into which emails will be written. Defaults to the application
-
# <tt>tmp/mails</tt>.
-
#
-
# * <tt>raise_delivery_errors</tt> - Whether or not errors should be raised if the email fails to be delivered.
-
#
-
# * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default),
-
# <tt>:sendmail</tt>, <tt>:test</tt>, and <tt>:file</tt>. Or you may provide a custom delivery method
-
# object e.g. MyOwnDeliveryMethodClass. See the Mail gem documentation on the interface you need to
-
# implement for a custom delivery agent.
-
#
-
# * <tt>perform_deliveries</tt> - Determines whether emails are actually sent from Action Mailer when you
-
# call <tt>.deliver</tt> on an mail message or on an Action Mailer method. This is on by default but can
-
# be turned off to aid in functional testing.
-
#
-
# * <tt>deliveries</tt> - Keeps an array of all the emails sent out through the Action Mailer with
-
# <tt>delivery_method :test</tt>. Most useful for unit and functional testing.
-
1
class Base < AbstractController::Base
-
1
include DeliveryMethods
-
1
abstract!
-
-
1
include AbstractController::Logger
-
1
include AbstractController::Rendering
-
1
include AbstractController::Layouts
-
1
include AbstractController::Helpers
-
1
include AbstractController::Translation
-
1
include AbstractController::AssetPaths
-
1
include AbstractController::Callbacks
-
-
1
self.protected_instance_variables = [:@_action_has_layout]
-
-
1
helper ActionMailer::MailHelper
-
-
1
private_class_method :new #:nodoc:
-
-
1
class_attribute :default_params
-
1
self.default_params = {
-
mime_version: "1.0",
-
charset: "UTF-8",
-
content_type: "text/plain",
-
parts_order: [ "text/plain", "text/enriched", "text/html" ]
-
}.freeze
-
-
1
class << self
-
# Register one or more Observers which will be notified when mail is delivered.
-
1
def register_observers(*observers)
-
1
observers.flatten.compact.each { |observer| register_observer(observer) }
-
end
-
-
# Register one or more Interceptors which will be called before mail is sent.
-
1
def register_interceptors(*interceptors)
-
1
interceptors.flatten.compact.each { |interceptor| register_interceptor(interceptor) }
-
end
-
-
# Register an Observer which will be notified when mail is delivered.
-
# Either a class or a string can be passed in as the Observer. If a string is passed in
-
# it will be <tt>constantize</tt>d.
-
1
def register_observer(observer)
-
delivery_observer = (observer.is_a?(String) ? observer.constantize : observer)
-
Mail.register_observer(delivery_observer)
-
end
-
-
# Register an Interceptor which will be called before mail is sent.
-
# Either a class or a string can be passed in as the Interceptor. If a string is passed in
-
# it will be <tt>constantize</tt>d.
-
1
def register_interceptor(interceptor)
-
delivery_interceptor = (interceptor.is_a?(String) ? interceptor.constantize : interceptor)
-
Mail.register_interceptor(delivery_interceptor)
-
end
-
-
1
def mailer_name
-
8
@mailer_name ||= anonymous? ? "anonymous" : name.underscore
-
end
-
1
attr_writer :mailer_name
-
1
alias :controller_path :mailer_name
-
-
1
def default(value = nil)
-
3
self.default_params = default_params.merge(value).freeze if value
-
3
default_params
-
end
-
# Allows to set defaults through app configuration:
-
#
-
# config.action_mailer.default_options = { from: "no-reply@example.org" }
-
1
alias :default_options= :default
-
-
# Receives a raw email, parses it into an email object, decodes it,
-
# instantiates a new mailer, and passes the email object to the mailer
-
# object's +receive+ method. If you want your mailer to be able to
-
# process incoming messages, you'll need to implement a +receive+
-
# method that accepts the raw email string as a parameter:
-
#
-
# class MyMailer < ActionMailer::Base
-
# def receive(mail)
-
# ...
-
# end
-
# end
-
1
def receive(raw_mail)
-
ActiveSupport::Notifications.instrument("receive.action_mailer") do |payload|
-
mail = Mail.new(raw_mail)
-
set_payload_for_mail(payload, mail)
-
new.receive(mail)
-
end
-
end
-
-
# Wraps an email delivery inside of Active Support Notifications instrumentation. This
-
# method is actually called by the <tt>Mail::Message</tt> object itself through a callback
-
# when you call <tt>:deliver</tt> on the Mail::Message, calling +deliver_mail+ directly
-
# and passing a Mail::Message will do nothing except tell the logger you sent the email.
-
1
def deliver_mail(mail) #:nodoc:
-
ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload|
-
set_payload_for_mail(payload, mail)
-
yield # Let Mail do the delivery actions
-
end
-
end
-
-
1
def respond_to?(method, include_private = false) #:nodoc:
-
9
super || action_methods.include?(method.to_s)
-
end
-
-
1
protected
-
-
1
def set_payload_for_mail(payload, mail) #:nodoc:
-
payload[:mailer] = name
-
payload[:message_id] = mail.message_id
-
payload[:subject] = mail.subject
-
payload[:to] = mail.to
-
payload[:from] = mail.from
-
payload[:bcc] = mail.bcc if mail.bcc.present?
-
payload[:cc] = mail.cc if mail.cc.present?
-
payload[:date] = mail.date
-
payload[:mail] = mail.encoded
-
end
-
-
1
def method_missing(method_name, *args)
-
2
if respond_to?(method_name)
-
2
new(method_name, *args).message
-
else
-
super
-
end
-
end
-
end
-
-
1
attr_internal :message
-
-
# Instantiate a new mailer object. If +method_name+ is not +nil+, the mailer
-
# will be initialized according to the named method. If not, the mailer will
-
# remain uninitialized (useful when you only need to invoke the "receive"
-
# method, for instance).
-
1
def initialize(method_name=nil, *args)
-
2
super()
-
2
@_mail_was_called = false
-
2
@_message = Mail.new
-
2
process(method_name, *args) if method_name
-
end
-
-
1
def process(*args) #:nodoc:
-
2
lookup_context.skip_default_locale!
-
-
2
super
-
2
@_message = NullMail.new unless @_mail_was_called
-
end
-
-
1
class NullMail #:nodoc:
-
1
def body; '' end
-
-
1
def method_missing(*args)
-
nil
-
end
-
end
-
-
1
def mailer_name
-
self.class.mailer_name
-
end
-
-
# Allows you to pass random and unusual headers to the new <tt>Mail::Message</tt> object
-
# which will add them to itself.
-
#
-
# headers['X-Special-Domain-Specific-Header'] = "SecretValue"
-
#
-
# You can also pass a hash into headers of header field names and values, which
-
# will then be set on the Mail::Message object:
-
#
-
# headers 'X-Special-Domain-Specific-Header' => "SecretValue",
-
# 'In-Reply-To' => incoming.message_id
-
#
-
# The resulting Mail::Message will have the following in its header:
-
#
-
# X-Special-Domain-Specific-Header: SecretValue
-
1
def headers(args = nil)
-
if args
-
@_message.headers(args)
-
else
-
@_message
-
end
-
end
-
-
# Allows you to add attachments to an email, like so:
-
#
-
# mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
-
#
-
# If you do this, then Mail will take the file name and work out the mime type
-
# set the Content-Type, Content-Disposition, Content-Transfer-Encoding and
-
# base64 encode the contents of the attachment all for you.
-
#
-
# You can also specify overrides if you want by passing a hash instead of a string:
-
#
-
# mail.attachments['filename.jpg'] = {mime_type: 'application/x-gzip',
-
# content: File.read('/path/to/filename.jpg')}
-
#
-
# If you want to use a different encoding than Base64, you can pass an encoding in,
-
# but then it is up to you to pass in the content pre-encoded, and don't expect
-
# Mail to know how to decode this data:
-
#
-
# file_content = SpecialEncode(File.read('/path/to/filename.jpg'))
-
# mail.attachments['filename.jpg'] = {mime_type: 'application/x-gzip',
-
# encoding: 'SpecialEncoding',
-
# content: file_content }
-
#
-
# You can also search for specific attachments:
-
#
-
# # By Filename
-
# mail.attachments['filename.jpg'] # => Mail::Part object or nil
-
#
-
# # or by index
-
# mail.attachments[0] # => Mail::Part (first attachment)
-
#
-
1
def attachments
-
@_message.attachments
-
end
-
-
# The main method that creates the message and renders the email templates. There are
-
# two ways to call this method, with a block, or without a block.
-
#
-
# Both methods accept a headers hash. This hash allows you to specify the most used headers
-
# in an email message, these are:
-
#
-
# * <tt>:subject</tt> - The subject of the message, if this is omitted, Action Mailer will
-
# ask the Rails I18n class for a translated <tt>:subject</tt> in the scope of
-
# <tt>[mailer_scope, action_name]</tt> or if this is missing, will translate the
-
# humanized version of the <tt>action_name</tt>
-
# * <tt>:to</tt> - Who the message is destined for, can be a string of addresses, or an array
-
# of addresses.
-
# * <tt>:from</tt> - Who the message is from
-
# * <tt>:cc</tt> - Who you would like to Carbon-Copy on this email, can be a string of addresses,
-
# or an array of addresses.
-
# * <tt>:bcc</tt> - Who you would like to Blind-Carbon-Copy on this email, can be a string of
-
# addresses, or an array of addresses.
-
# * <tt>:reply_to</tt> - Who to set the Reply-To header of the email to.
-
# * <tt>:date</tt> - The date to say the email was sent on.
-
#
-
# You can set default values for any of the above headers (except :date) by using the <tt>default</tt>
-
# class method:
-
#
-
# class Notifier < ActionMailer::Base
-
# default from: 'no-reply@test.lindsaar.net',
-
# bcc: 'email_logger@test.lindsaar.net',
-
# reply_to: 'bounces@test.lindsaar.net'
-
# end
-
#
-
# If you need other headers not listed above, you can either pass them in
-
# as part of the headers hash or use the <tt>headers['name'] = value</tt>
-
# method.
-
#
-
# When a <tt>:return_path</tt> is specified as header, that value will be used as the 'envelope from'
-
# address for the Mail message. Setting this is useful when you want delivery notifications
-
# sent to a different address than the one in <tt>:from</tt>. Mail will actually use the
-
# <tt>:return_path</tt> in preference to the <tt>:sender</tt> in preference to the <tt>:from</tt>
-
# field for the 'envelope from' value.
-
#
-
# If you do not pass a block to the +mail+ method, it will find all templates in the
-
# view paths using by default the mailer name and the method name that it is being
-
# called from, it will then create parts for each of these templates intelligently,
-
# making educated guesses on correct content type and sequence, and return a fully
-
# prepared Mail::Message ready to call <tt>:deliver</tt> on to send.
-
#
-
# For example:
-
#
-
# class Notifier < ActionMailer::Base
-
# default from: 'no-reply@test.lindsaar.net',
-
#
-
# def welcome
-
# mail(to: 'mikel@test.lindsaar.net')
-
# end
-
# end
-
#
-
# Will look for all templates at "app/views/notifier" with name "welcome".
-
# If no welcome template exists, it will raise an ActionView::MissingTemplate error.
-
#
-
# However, those can be customized:
-
#
-
# mail(template_path: 'notifications', template_name: 'another')
-
#
-
# And now it will look for all templates at "app/views/notifications" with name "another".
-
#
-
# If you do pass a block, you can render specific templates of your choice:
-
#
-
# mail(to: 'mikel@test.lindsaar.net') do |format|
-
# format.text
-
# format.html
-
# end
-
#
-
# You can even render text directly without using a template:
-
#
-
# mail(to: 'mikel@test.lindsaar.net') do |format|
-
# format.text { render text: "Hello Mikel!" }
-
# format.html { render text: "<h1>Hello Mikel!</h1>" }
-
# end
-
#
-
# Which will render a <tt>multipart/alternative</tt> email with <tt>text/plain</tt> and
-
# <tt>text/html</tt> parts.
-
#
-
# The block syntax also allows you to customize the part headers if desired:
-
#
-
# mail(to: 'mikel@test.lindsaar.net') do |format|
-
# format.text(content_transfer_encoding: "base64")
-
# format.html
-
# end
-
#
-
1
def mail(headers = {}, &block)
-
2
@_mail_was_called = true
-
2
m = @_message
-
-
# At the beginning, do not consider class default for content_type
-
2
content_type = headers[:content_type]
-
-
# Call all the procs (if any)
-
2
class_default = self.class.default
-
2
default_values = class_default.merge(class_default) do |k,v|
-
10
v.is_a?(Proc) ? instance_eval(&v) : v
-
end
-
-
# Handle defaults
-
2
headers = headers.reverse_merge(default_values)
-
2
headers[:subject] ||= default_i18n_subject
-
-
# Apply charset at the beginning so all fields are properly quoted
-
2
m.charset = charset = headers[:charset]
-
-
# Set configure delivery behavior
-
2
wrap_delivery_behavior!(headers.delete(:delivery_method),headers.delete(:delivery_method_options))
-
-
# Assign all headers except parts_order, content_type and body
-
2
assignable = headers.except(:parts_order, :content_type, :body, :template_name, :template_path)
-
12
assignable.each { |k, v| m[k] = v }
-
-
# Render the templates and blocks
-
2
responses = collect_responses(headers, &block)
-
2
create_parts_from_responses(m, responses)
-
-
# Setup content type, reapply charset and handle parts order
-
2
m.content_type = set_content_type(m, content_type, headers[:content_type])
-
2
m.charset = charset
-
-
2
if m.multipart?
-
m.body.set_sort_order(headers[:parts_order])
-
m.body.sort_parts!
-
end
-
-
2
m
-
end
-
-
1
protected
-
-
1
def set_content_type(m, user_content_type, class_default)
-
2
params = m.content_type_parameters || {}
-
case
-
when user_content_type.present?
-
user_content_type
-
when m.has_attachments?
-
if m.attachments.detect { |a| a.inline? }
-
["multipart", "related", params]
-
else
-
["multipart", "mixed", params]
-
end
-
when m.multipart?
-
["multipart", "alternative", params]
-
else
-
2
m.content_type || class_default
-
2
end
-
end
-
-
# Translates the +subject+ using Rails I18n class under <tt>[mailer_scope, action_name]</tt> scope.
-
# If it does not find a translation for the +subject+ under the specified scope it will default to a
-
# humanized version of the <tt>action_name</tt>.
-
# If the subject has interpolations, you can pass them through the +interpolations+ parameter.
-
1
def default_i18n_subject(interpolations = {})
-
2
mailer_scope = self.class.mailer_name.tr('/', '.')
-
2
I18n.t(:subject, interpolations.merge(scope: [mailer_scope, action_name], default: action_name.humanize))
-
end
-
-
1
def collect_responses(headers) #:nodoc:
-
2
responses = []
-
-
2
if block_given?
-
collector = ActionMailer::Collector.new(lookup_context) { render(action_name) }
-
yield(collector)
-
responses = collector.responses
-
elsif headers[:body]
-
responses << {
-
body: headers.delete(:body),
-
content_type: self.class.default[:content_type] || "text/plain"
-
}
-
else
-
2
templates_path = headers.delete(:template_path) || self.class.mailer_name
-
2
templates_name = headers.delete(:template_name) || action_name
-
-
2
each_template(Array(templates_path), templates_name) do |template|
-
2
self.formats = template.formats
-
-
responses << {
-
body: render(template: template),
-
content_type: template.type.to_s
-
2
}
-
end
-
end
-
-
2
responses
-
end
-
-
1
def each_template(paths, name, &block) #:nodoc:
-
2
templates = lookup_context.find_all(name, paths)
-
2
if templates.empty?
-
raise ActionView::MissingTemplate.new(paths, name, paths, false, 'mailer')
-
else
-
2
templates.uniq { |t| t.formats }.each(&block)
-
end
-
end
-
-
1
def create_parts_from_responses(m, responses) #:nodoc:
-
2
if responses.size == 1 && !m.has_attachments?
-
6
responses[0].each { |k,v| m[k] = v }
-
elsif responses.size > 1 && m.has_attachments?
-
container = Mail::Part.new
-
container.content_type = "multipart/alternative"
-
responses.each { |r| insert_part(container, r, m.charset) }
-
m.add_part(container)
-
else
-
responses.each { |r| insert_part(m, r, m.charset) }
-
end
-
end
-
-
1
def insert_part(container, response, charset) #:nodoc:
-
response[:charset] ||= charset
-
part = Mail::Part.new(response)
-
container.add_part(part)
-
end
-
-
1
ActiveSupport.run_load_hooks(:action_mailer, self)
-
end
-
end
-
1
require 'abstract_controller/collector'
-
1
require 'active_support/core_ext/hash/reverse_merge'
-
1
require 'active_support/core_ext/array/extract_options'
-
-
1
module ActionMailer
-
1
class Collector
-
1
include AbstractController::Collector
-
1
attr_reader :responses
-
-
1
def initialize(context, &block)
-
@context = context
-
@responses = []
-
@default_render = block
-
end
-
-
1
def any(*args, &block)
-
options = args.extract_options!
-
raise ArgumentError, "You have to supply at least one format" if args.empty?
-
args.each { |type| send(type, options.dup, &block) }
-
end
-
1
alias :all :any
-
-
1
def custom(mime, options = {})
-
options.reverse_merge!(content_type: mime.to_s)
-
@context.formats = [mime.to_sym]
-
options[:body] = block_given? ? yield : @default_render.call
-
@responses << options
-
end
-
end
-
end
-
1
require 'tmpdir'
-
-
1
module ActionMailer
-
# This module handles everything related to mail delivery, from registering
-
# new delivery methods to configuring the mail object to be sent.
-
1
module DeliveryMethods
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
class_attribute :delivery_methods, :delivery_method
-
-
# Do not make this inheritable, because we always want it to propagate
-
1
cattr_accessor :raise_delivery_errors
-
1
self.raise_delivery_errors = true
-
-
1
cattr_accessor :perform_deliveries
-
1
self.perform_deliveries = true
-
-
1
self.delivery_methods = {}.freeze
-
1
self.delivery_method = :smtp
-
-
1
add_delivery_method :smtp, Mail::SMTP,
-
address: "localhost",
-
port: 25,
-
domain: 'localhost.localdomain',
-
user_name: nil,
-
password: nil,
-
authentication: nil,
-
enable_starttls_auto: true
-
-
1
add_delivery_method :file, Mail::FileDelivery,
-
location: defined?(Rails.root) ? "#{Rails.root}/tmp/mails" : "#{Dir.tmpdir}/mails"
-
-
1
add_delivery_method :sendmail, Mail::Sendmail,
-
location: '/usr/sbin/sendmail',
-
arguments: '-i -t'
-
-
1
add_delivery_method :test, Mail::TestMailer
-
end
-
-
1
module ClassMethods
-
# Provides a list of emails that have been delivered by Mail::TestMailer
-
1
delegate :deliveries, :deliveries=, to: Mail::TestMailer
-
-
# Adds a new delivery method through the given class using the given
-
# symbol as alias and the default options supplied.
-
#
-
# add_delivery_method :sendmail, Mail::Sendmail,
-
# location: '/usr/sbin/sendmail',
-
# arguments: '-i -t'
-
1
def add_delivery_method(symbol, klass, default_options={})
-
4
class_attribute(:"#{symbol}_settings") unless respond_to?(:"#{symbol}_settings")
-
4
send(:"#{symbol}_settings=", default_options)
-
4
self.delivery_methods = delivery_methods.merge(symbol.to_sym => klass).freeze
-
end
-
-
1
def wrap_delivery_behavior(mail, method=nil, options=nil) # :nodoc:
-
2
method ||= self.delivery_method
-
2
mail.delivery_handler = self
-
-
2
case method
-
when NilClass
-
raise "Delivery method cannot be nil"
-
when Symbol
-
2
if klass = delivery_methods[method]
-
2
mail.delivery_method(klass, (send(:"#{method}_settings") || {}).merge(options || {}))
-
else
-
raise "Invalid delivery method #{method.inspect}"
-
end
-
else
-
mail.delivery_method(method)
-
end
-
-
2
mail.perform_deliveries = perform_deliveries
-
2
mail.raise_delivery_errors = raise_delivery_errors
-
end
-
end
-
-
1
def wrap_delivery_behavior!(*args) # :nodoc:
-
2
self.class.wrap_delivery_behavior(message, *args)
-
end
-
end
-
end
-
1
module ActionMailer
-
1
class LogSubscriber < ActiveSupport::LogSubscriber
-
1
def deliver(event)
-
return unless logger.info?
-
recipients = Array(event.payload[:to]).join(', ')
-
info("\nSent mail to #{recipients} (#{event.duration.round(1)}ms)")
-
debug(event.payload[:mail])
-
end
-
-
1
def receive(event)
-
return unless logger.info?
-
info("\nReceived mail (#{event.duration.round(1)}ms)")
-
debug(event.payload[:mail])
-
end
-
-
1
def logger
-
ActionMailer::Base.logger
-
end
-
end
-
end
-
-
1
ActionMailer::LogSubscriber.attach_to :action_mailer
-
1
module ActionMailer
-
1
module MailHelper
-
# Take the text and format it, indented two spaces for each line, and
-
# wrapped at 72 columns.
-
1
def block_format(text)
-
formatted = text.split(/\n\r?\n/).collect { |paragraph|
-
format_paragraph(paragraph)
-
}.join("\n\n")
-
-
# Make list points stand on their own line
-
formatted.gsub!(/[ ]*([*]+) ([^*]*)/) { |s| " #{$1} #{$2.strip}\n" }
-
formatted.gsub!(/[ ]*([#]+) ([^#]*)/) { |s| " #{$1} #{$2.strip}\n" }
-
-
formatted
-
end
-
-
# Access the mailer instance.
-
1
def mailer
-
@_controller
-
end
-
-
# Access the message instance.
-
1
def message
-
@_message
-
end
-
-
# Access the message attachments list.
-
1
def attachments
-
@_message.attachments
-
end
-
-
# Returns +text+ wrapped at +len+ columns and indented +indent+ spaces.
-
#
-
# my_text = 'Here is a sample text with more than 40 characters'
-
#
-
# format_paragraph(my_text, 25, 4)
-
# # => " Here is a sample text with\n more than 40 characters"
-
1
def format_paragraph(text, len = 72, indent = 2)
-
sentences = [[]]
-
-
text.split.each do |word|
-
if sentences.first.present? && (sentences.last + [word]).join(' ').length > len
-
sentences << [word]
-
else
-
sentences.last << word
-
end
-
end
-
-
sentences.map { |sentence|
-
"#{" " * indent}#{sentence.join(' ')}"
-
}.join "\n"
-
end
-
end
-
end
-
1
module ActionController
-
1
module Testing
-
1
extend ActiveSupport::Concern
-
-
1
include RackDelegation
-
-
# TODO : Rewrite tests using controller.headers= to use Rack env
-
1
def headers=(new_headers)
-
@_response ||= ActionDispatch::Response.new
-
@_response.headers.replace(new_headers)
-
end
-
-
# Behavior specific to functional tests
-
1
module Functional # :nodoc:
-
1
def set_response!(request)
-
end
-
-
1
def recycle!
-
12
@_url_options = nil
-
12
self.response_body = nil
-
12
self.formats = nil
-
12
self.params = nil
-
end
-
end
-
-
1
module ClassMethods
-
1
def before_filters
-
_process_action_callbacks.find_all{|x| x.kind == :before}.map{|x| x.name}
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/string/output_safety'
-
-
1
module ActionView
-
1
class OutputBuffer < ActiveSupport::SafeBuffer #:nodoc:
-
1
def initialize(*)
-
2
super
-
2
encode!
-
end
-
-
1
def <<(value)
-
return self if value.nil?
-
super(value.to_s)
-
end
-
1
alias :append= :<<
-
-
1
def safe_concat(value)
-
return self if value.nil?
-
super(value.to_s)
-
end
-
1
alias :safe_append= :safe_concat
-
end
-
-
1
class StreamingBuffer #:nodoc:
-
1
def initialize(block)
-
@block = block
-
end
-
-
1
def <<(value)
-
value = value.to_s
-
value = ERB::Util.h(value) unless value.html_safe?
-
@block.call(value)
-
end
-
1
alias :concat :<<
-
1
alias :append= :<<
-
-
1
def safe_concat(value)
-
@block.call(value.to_s)
-
end
-
1
alias :safe_append= :safe_concat
-
-
1
def html_safe?
-
true
-
end
-
-
1
def html_safe
-
self
-
end
-
end
-
end
-
1
require 'active_support/core_ext/string/output_safety'
-
-
1
module ActionView
-
1
class OutputFlow #:nodoc:
-
1
attr_reader :content
-
-
1
def initialize
-
3
@content = Hash.new { |h,k| h[k] = ActiveSupport::SafeBuffer.new }
-
end
-
-
# Called by _layout_for to read stored values.
-
1
def get(key)
-
@content[key]
-
end
-
-
# Called by each renderer object to set the layout contents.
-
1
def set(key, value)
-
1
@content[key] = value
-
end
-
-
# Called by content_for
-
1
def append(key, value)
-
@content[key] << value
-
end
-
1
alias_method :append!, :append
-
-
end
-
-
1
class StreamingFlow < OutputFlow #:nodoc:
-
1
def initialize(view, fiber)
-
@view = view
-
@parent = nil
-
@child = view.output_buffer
-
@content = view.view_flow.content
-
@fiber = fiber
-
@root = Fiber.current.object_id
-
end
-
-
# Try to get an stored content. If the content
-
# is not available and we are inside the layout
-
# fiber, we set that we are waiting for the given
-
# key and yield.
-
1
def get(key)
-
return super if @content.key?(key)
-
-
if inside_fiber?
-
view = @view
-
-
begin
-
@waiting_for = key
-
view.output_buffer, @parent = @child, view.output_buffer
-
Fiber.yield
-
ensure
-
@waiting_for = nil
-
view.output_buffer, @child = @parent, view.output_buffer
-
end
-
end
-
-
super
-
end
-
-
# Appends the contents for the given key. This is called
-
# by provides and resumes back to the fiber if it is
-
# the key it is waiting for.
-
1
def append!(key, value)
-
super
-
@fiber.resume if @waiting_for == key
-
end
-
-
1
private
-
-
1
def inside_fiber?
-
Fiber.current.object_id != @root
-
end
-
end
-
end
-
1
require 'thread_safe'
-
1
require 'active_support/core_ext/module/remove_method'
-
1
require 'active_support/core_ext/module/attribute_accessors'
-
-
1
module ActionView
-
# = Action View Lookup Context
-
#
-
# LookupContext is the object responsible to hold all information required to lookup
-
# templates, i.e. view paths and details. The LookupContext is also responsible to
-
# generate a key, given to view paths, used in the resolver cache lookup. Since
-
# this key is generated just once during the request, it speeds up all cache accesses.
-
1
class LookupContext #:nodoc:
-
1
attr_accessor :prefixes, :rendered_format
-
-
1
mattr_accessor :fallbacks
-
1
@@fallbacks = FallbackFileSystemResolver.instances
-
-
1
mattr_accessor :registered_details
-
1
self.registered_details = []
-
-
1
def self.register_detail(name, options = {}, &block)
-
3
self.registered_details << name
-
9
initialize = registered_details.map { |n| "@details[:#{n}] = details[:#{n}] || default_#{n}" }
-
-
3
Accessors.send :define_method, :"default_#{name}", &block
-
3
Accessors.module_eval <<-METHOD, __FILE__, __LINE__ + 1
-
def #{name}
-
@details.fetch(:#{name}, [])
-
end
-
-
def #{name}=(value)
-
value = value.present? ? Array(value) : default_#{name}
-
_set_detail(:#{name}, value) if value != @details[:#{name}]
-
end
-
-
remove_possible_method :initialize_details
-
def initialize_details(details)
-
#{initialize.join("\n")}
-
end
-
METHOD
-
end
-
-
# Holds accessors for the registered details.
-
1
module Accessors #:nodoc:
-
end
-
-
1
register_detail(:locale) do
-
14
locales = [I18n.locale]
-
14
locales.concat(I18n.fallbacks[I18n.locale]) if I18n.respond_to? :fallbacks
-
14
locales << I18n.default_locale
-
14
locales.uniq!
-
14
locales
-
end
-
27
register_detail(:formats) { ActionView::Base.default_formats || [:html, :text, :js, :css, :xml, :json] }
-
15
register_detail(:handlers){ Template::Handlers.extensions }
-
-
1
class DetailsKey #:nodoc:
-
1
alias :eql? :equal?
-
1
alias :object_hash :hash
-
-
1
attr_reader :hash
-
1
@details_keys = ThreadSafe::Cache.new
-
-
1
def self.get(details)
-
5
if details[:formats]
-
5
details = details.dup
-
5
syms = Set.new Mime::SET.symbols
-
5
details[:formats] = details[:formats].select { |v|
-
45
syms.include? v
-
}
-
end
-
5
@details_keys[details] ||= new
-
end
-
-
1
def self.clear
-
@details_keys.clear
-
end
-
-
1
def initialize
-
3
@hash = object_hash
-
end
-
end
-
-
# Add caching behavior on top of Details.
-
1
module DetailsCache
-
1
attr_accessor :cache
-
-
# Calculate the details key. Remove the handlers from calculation to improve performance
-
# since the user cannot modify it explicitly.
-
1
def details_key #:nodoc:
-
9
@details_key ||= DetailsKey.get(@details) if @cache
-
end
-
-
# Temporary skip passing the details_key forward.
-
1
def disable_cache
-
old_value, @cache = @cache, false
-
yield
-
ensure
-
@cache = old_value
-
end
-
-
1
protected
-
-
1
def _set_detail(key, value)
-
14
@details = @details.dup if @details_key
-
14
@details_key = nil
-
14
@details[key] = value
-
end
-
end
-
-
# Helpers related to template lookup using the lookup context information.
-
1
module ViewPaths
-
1
attr_reader :view_paths, :html_fallback_for_js
-
-
# Whenever setting view paths, makes a copy so we can manipulate then in
-
# instance objects as we wish.
-
1
def view_paths=(paths)
-
14
@view_paths = ActionView::PathSet.new(Array(paths))
-
end
-
-
1
def find(name, prefixes = [], partial = false, keys = [], options = {})
-
1
@view_paths.find(*args_for_lookup(name, prefixes, partial, keys, options))
-
end
-
1
alias :find_template :find
-
-
1
def find_all(name, prefixes = [], partial = false, keys = [], options = {})
-
8
@view_paths.find_all(*args_for_lookup(name, prefixes, partial, keys, options))
-
end
-
-
1
def exists?(name, prefixes = [], partial = false, keys = [], options = {})
-
@view_paths.exists?(*args_for_lookup(name, prefixes, partial, keys, options))
-
end
-
1
alias :template_exists? :exists?
-
-
# Add fallbacks to the view paths. Useful in cases you are rendering a :file.
-
1
def with_fallbacks
-
added_resolvers = 0
-
self.class.fallbacks.each do |resolver|
-
next if view_paths.include?(resolver)
-
view_paths.push(resolver)
-
added_resolvers += 1
-
end
-
yield
-
ensure
-
added_resolvers.times { view_paths.pop }
-
end
-
-
1
protected
-
-
1
def args_for_lookup(name, prefixes, partial, keys, details_options) #:nodoc:
-
9
name, prefixes = normalize_name(name, prefixes)
-
9
details, details_key = detail_args_for(details_options)
-
9
[name, prefixes, partial || false, details, details_key, keys]
-
end
-
-
# Compute details hash and key according to user options (e.g. passed from #render).
-
1
def detail_args_for(options)
-
9
return @details, details_key if options.empty? # most common path.
-
user_details = @details.merge(options)
-
[user_details, DetailsKey.get(user_details)]
-
end
-
-
# Support legacy foo.erb names even though we now ignore .erb
-
# as well as incorrectly putting part of the path in the template
-
# name instead of the prefix.
-
1
def normalize_name(name, prefixes) #:nodoc:
-
9
prefixes = prefixes.presence
-
9
parts = name.to_s.split('/')
-
9
parts.shift if parts.first.empty?
-
9
name = parts.pop
-
-
9
return name, prefixes || [""] if parts.empty?
-
-
2
parts = parts.join('/')
-
4
prefixes = prefixes ? prefixes.map { |p| "#{p}/#{parts}" } : [parts]
-
-
2
return name, prefixes
-
end
-
end
-
-
1
include Accessors
-
1
include DetailsCache
-
1
include ViewPaths
-
-
1
def initialize(view_paths, details = {}, prefixes = [])
-
14
@details, @details_key = {}, nil
-
14
@skip_default_locale = false
-
14
@cache = true
-
14
@prefixes = prefixes
-
14
@rendered_format = nil
-
-
14
self.view_paths = view_paths
-
14
initialize_details(details)
-
end
-
-
# Override formats= to expand ["*/*"] values and automatically
-
# add :html as fallback to :js.
-
1
def formats=(values)
-
36
if values
-
24
values.concat(default_formats) if values.delete "*/*"
-
24
if values == [:js]
-
values << :html
-
@html_fallback_for_js = true
-
end
-
end
-
36
super(values)
-
end
-
-
# Do not use the default locale on template lookup.
-
1
def skip_default_locale!
-
2
@skip_default_locale = true
-
2
self.locale = nil
-
end
-
-
# Override locale to return a symbol instead of array.
-
1
def locale
-
@details[:locale].first
-
end
-
-
# Overload locale= to also set the I18n.locale. If the current I18n.config object responds
-
# to original_config, it means that it's has a copy of the original I18n configuration and it's
-
# acting as proxy, which we need to skip.
-
1
def locale=(value)
-
2
if value
-
config = I18n.config.respond_to?(:original_config) ? I18n.config.original_config : I18n.config
-
config.locale = value
-
end
-
-
2
super(@skip_default_locale ? I18n.locale : default_locale)
-
end
-
-
# A method which only uses the first format in the formats array for layout lookup.
-
1
def with_layout_format
-
3
if formats.size == 1
-
3
yield
-
else
-
old_formats = formats
-
_set_detail(:formats, formats[0,1])
-
-
begin
-
yield
-
ensure
-
_set_detail(:formats, old_formats)
-
end
-
end
-
end
-
end
-
end
-
1
module ActionView
-
# This class defines the interface for a renderer. Each class that
-
# subclasses +AbstractRenderer+ is used by the base +Renderer+ class to
-
# render a specific type of object.
-
#
-
# The base +Renderer+ class uses its +render+ method to delegate to the
-
# renderers. These currently consist of
-
#
-
# PartialRenderer - Used for rendering partials
-
# TemplateRenderer - Used for rendering other types of templates
-
# StreamingTemplateRenderer - Used for streaming
-
#
-
# Whenever the +render+ method is called on the base +Renderer+ class, a new
-
# renderer object of the correct type is created, and the +render+ method on
-
# that new object is called in turn. This abstracts the setup and rendering
-
# into a separate classes for partials and templates.
-
1
class AbstractRenderer #:nodoc:
-
1
delegate :find_template, :template_exists?, :with_fallbacks, :with_layout_format, :formats, :to => :@lookup_context
-
-
1
def initialize(lookup_context)
-
3
@lookup_context = lookup_context
-
end
-
-
1
def render
-
raise NotImplementedError
-
end
-
-
1
protected
-
-
1
def extract_details(options)
-
3
@lookup_context.registered_details.each_with_object({}) do |key, details|
-
9
next unless value = options[key]
-
details[key] = Array(value)
-
end
-
end
-
-
1
def instrument(name, options={})
-
6
ActiveSupport::Notifications.instrument("render_#{name}.action_view", options){ yield }
-
end
-
-
1
def prepend_formats(formats)
-
3
formats = Array(formats)
-
3
return if formats.empty? || @lookup_context.html_fallback_for_js
-
3
@lookup_context.formats = formats | @lookup_context.formats
-
end
-
end
-
end
-
1
module ActionView
-
# This is the main entry point for rendering. It basically delegates
-
# to other objects like TemplateRenderer and PartialRenderer which
-
# actually renders the template.
-
#
-
# The Renderer will parse the options from the +render+ or +render_body+
-
# method and render a partial or a template based on the options. The
-
# +TemplateRenderer+ and +PartialRenderer+ objects are wrappers which do all
-
# the setup and logic necessary to render a view and a new object is created
-
# each time +render+ is called.
-
1
class Renderer
-
1
attr_accessor :lookup_context
-
-
1
def initialize(lookup_context)
-
3
@lookup_context = lookup_context
-
end
-
-
# Main render entry point shared by AV and AC.
-
1
def render(context, options)
-
3
if options.key?(:partial)
-
render_partial(context, options)
-
else
-
3
render_template(context, options)
-
end
-
end
-
-
# Render but returns a valid Rack body. If fibers are defined, we return
-
# a streaming body that renders the template piece by piece.
-
#
-
# Note that partials are not supported to be rendered with streaming,
-
# so in such cases, we just wrap them in an array.
-
1
def render_body(context, options)
-
if options.key?(:partial)
-
[render_partial(context, options)]
-
else
-
StreamingTemplateRenderer.new(@lookup_context).render(context, options)
-
end
-
end
-
-
# Direct accessor to template rendering.
-
1
def render_template(context, options) #:nodoc:
-
3
TemplateRenderer.new(@lookup_context).render(context, options)
-
end
-
-
# Direct access to partial rendering.
-
1
def render_partial(context, options, &block) #:nodoc:
-
PartialRenderer.new(@lookup_context).render(context, options, block)
-
end
-
end
-
end
-
1
require 'active_support/core_ext/object/try'
-
-
1
module ActionView
-
1
class TemplateRenderer < AbstractRenderer #:nodoc:
-
1
def render(context, options)
-
3
@view = context
-
3
@details = extract_details(options)
-
3
template = determine_template(options)
-
3
context = @lookup_context
-
-
3
prepend_formats(template.formats)
-
-
3
unless context.rendered_format
-
3
context.rendered_format = template.formats.first || formats.first
-
end
-
-
3
render_template(template, options[:layout], options[:locals])
-
end
-
-
# Determine the template to be rendered using the given options.
-
1
def determine_template(options) #:nodoc:
-
3
keys = options.fetch(:locals, {}).keys
-
-
3
if options.key?(:text)
-
Template::Text.new(options[:text], formats.first)
-
3
elsif options.key?(:file)
-
with_fallbacks { find_template(options[:file], nil, false, keys, @details) }
-
3
elsif options.key?(:inline)
-
handler = Template.handler_for_extension(options[:type] || "erb")
-
Template.new(options[:inline], "inline template", handler, :locals => keys)
-
3
elsif options.key?(:template)
-
3
if options[:template].respond_to?(:render)
-
2
options[:template]
-
else
-
1
find_template(options[:template], options[:prefixes], false, keys, @details)
-
end
-
else
-
raise ArgumentError, "You invoked render but did not give any of :partial, :template, :inline, :file or :text option."
-
end
-
end
-
-
# Renders the given template. A string representing the layout can be
-
# supplied as well.
-
1
def render_template(template, layout_name = nil, locals = nil) #:nodoc:
-
3
view, locals = @view, locals || {}
-
-
3
render_with_layout(layout_name, locals) do |layout|
-
3
instrument(:template, :identifier => template.identifier, :layout => layout.try(:virtual_path)) do
-
3
template.render(view, locals) { |*name| view._layout_for(*name) }
-
end
-
end
-
end
-
-
1
def render_with_layout(path, locals) #:nodoc:
-
3
layout = path && find_layout(path, locals.keys)
-
3
content = yield(layout)
-
-
3
if layout
-
1
view = @view
-
1
view.view_flow.set(:layout, content)
-
1
layout.render(view, locals){ |*name| view._layout_for(*name) }
-
else
-
2
content
-
end
-
end
-
-
# This is the method which actually finds the layout using details in the lookup
-
# context object. If no layout is found, it checks if at least a layout with
-
# the given name exists across all details before raising the error.
-
1
def find_layout(layout, keys)
-
6
with_layout_format { resolve_layout(layout, keys) }
-
end
-
-
1
def resolve_layout(layout, keys)
-
6
case layout
-
when String
-
begin
-
if layout =~ /^\//
-
with_fallbacks { find_template(layout, nil, false, keys, @details) }
-
else
-
find_template(layout, nil, false, keys, @details)
-
end
-
rescue ActionView::MissingTemplate
-
all_details = @details.merge(:formats => @lookup_context.default_formats)
-
raise unless template_exists?(layout, nil, false, keys, all_details)
-
end
-
when Proc
-
3
resolve_layout(layout.call, keys)
-
when FalseClass
-
nil
-
else
-
3
layout
-
end
-
end
-
end
-
end
-
# -*- coding: utf-8 -*-
-
-
1
require 'active_support/core_ext/array/conversions'
-
1
require 'active_support/core_ext/string/inflections'
-
-
1
module ActiveModel
-
# == Active \Model \Errors
-
#
-
# Provides a modified +Hash+ that you can include in your object
-
# for handling error messages and interacting with Action Pack helpers.
-
#
-
# A minimal implementation could be:
-
#
-
# class Person
-
# # Required dependency for ActiveModel::Errors
-
# extend ActiveModel::Naming
-
#
-
# def initialize
-
# @errors = ActiveModel::Errors.new(self)
-
# end
-
#
-
# attr_accessor :name
-
# attr_reader :errors
-
#
-
# def validate!
-
# errors.add(:name, "can not be nil") if name == nil
-
# end
-
#
-
# # The following methods are needed to be minimally implemented
-
#
-
# def read_attribute_for_validation(attr)
-
# send(attr)
-
# end
-
#
-
# def Person.human_attribute_name(attr, options = {})
-
# attr
-
# end
-
#
-
# def Person.lookup_ancestors
-
# [self]
-
# end
-
# end
-
#
-
# The last three methods are required in your object for Errors to be
-
# able to generate error messages correctly and also handle multiple
-
# languages. Of course, if you extend your object with ActiveModel::Translation
-
# you will not need to implement the last two. Likewise, using
-
# ActiveModel::Validations will handle the validation related methods
-
# for you.
-
#
-
# The above allows you to do:
-
#
-
# person = Person.new
-
# person.validate! # => ["can not be nil"]
-
# person.errors.full_messages # => ["name can not be nil"]
-
# # etc..
-
1
class Errors
-
1
include Enumerable
-
-
1
CALLBACKS_OPTIONS = [:if, :unless, :on, :allow_nil, :allow_blank, :strict]
-
-
1
attr_reader :messages
-
-
# Pass in the instance of the object that is using the errors object.
-
#
-
# class Person
-
# def initialize
-
# @errors = ActiveModel::Errors.new(self)
-
# end
-
# end
-
1
def initialize(base)
-
24
@base = base
-
24
@messages = {}
-
end
-
-
1
def initialize_dup(other) # :nodoc:
-
@messages = other.messages.dup
-
super
-
end
-
-
# Clear the error messages.
-
#
-
# person.errors.full_messages # => ["name can not be nil"]
-
# person.errors.clear
-
# person.errors.full_messages # => []
-
1
def clear
-
29
messages.clear
-
end
-
-
# Returns +true+ if the error messages include an error for the given key
-
# +attribute+, +false+ otherwise.
-
#
-
# person.errors.messages # => {:name=>["can not be nil"]}
-
# person.errors.include?(:name) # => true
-
# person.errors.include?(:age) # => false
-
1
def include?(attribute)
-
(v = messages[attribute]) && v.any?
-
end
-
# aliases include?
-
1
alias :has_key? :include?
-
-
# Get messages for +key+.
-
#
-
# person.errors.messages # => {:name=>["can not be nil"]}
-
# person.errors.get(:name) # => ["can not be nil"]
-
# person.errors.get(:age) # => nil
-
1
def get(key)
-
52
messages[key]
-
end
-
-
# Set messages for +key+ to +value+.
-
#
-
# person.errors.get(:name) # => ["can not be nil"]
-
# person.errors.set(:name, ["can't be nil"])
-
# person.errors.get(:name) # => ["can't be nil"]
-
1
def set(key, value)
-
22
messages[key] = value
-
end
-
-
# Delete messages for +key+. Returns the deleted messages.
-
#
-
# person.errors.get(:name) # => ["can not be nil"]
-
# person.errors.delete(:name) # => ["can not be nil"]
-
# person.errors.get(:name) # => nil
-
1
def delete(key)
-
messages.delete(key)
-
end
-
-
# When passed a symbol or a name of a method, returns an array of errors
-
# for the method.
-
#
-
# person.errors[:name] # => ["can not be nil"]
-
# person.errors['name'] # => ["can not be nil"]
-
1
def [](attribute)
-
52
get(attribute.to_sym) || set(attribute.to_sym, [])
-
end
-
-
# Adds to the supplied attribute the supplied error message.
-
#
-
# person.errors[:name] = "must be set"
-
# person.errors[:name] # => ['must be set']
-
1
def []=(attribute, error)
-
self[attribute] << error
-
end
-
-
# Iterates through each error key, value pair in the error messages hash.
-
# Yields the attribute and the error for that attribute. If the attribute
-
# has more than one error message, yields once for each error message.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.each do |attribute, error|
-
# # Will yield :name and "can't be blank"
-
# end
-
#
-
# person.errors.add(:name, "must be specified")
-
# person.errors.each do |attribute, error|
-
# # Will yield :name and "can't be blank"
-
# # then yield :name and "must be specified"
-
# end
-
1
def each
-
63
messages.each_key do |attribute|
-
50
self[attribute].each { |error| yield attribute, error }
-
end
-
end
-
-
# Returns the number of error messages.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.size # => 1
-
# person.errors.add(:name, "must be specified")
-
# person.errors.size # => 2
-
1
def size
-
values.flatten.size
-
end
-
-
# Returns all message values.
-
#
-
# person.errors.messages # => {:name=>["can not be nil", "must be specified"]}
-
# person.errors.values # => [["can not be nil", "must be specified"]]
-
1
def values
-
messages.values
-
end
-
-
# Returns all message keys.
-
#
-
# person.errors.messages # => {:name=>["can not be nil", "must be specified"]}
-
# person.errors.keys # => [:name]
-
1
def keys
-
messages.keys
-
end
-
-
# Returns an array of error messages, with the attribute name included.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.add(:name, "must be specified")
-
# person.errors.to_a # => ["name can't be blank", "name must be specified"]
-
1
def to_a
-
full_messages
-
end
-
-
# Returns the number of error messages.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.count # => 1
-
# person.errors.add(:name, "must be specified")
-
# person.errors.count # => 2
-
1
def count
-
to_a.size
-
end
-
-
# Returns +true+ if no errors are found, +false+ otherwise.
-
# If the error message is a string it can be empty.
-
#
-
# person.errors.full_messages # => ["name can not be nil"]
-
# person.errors.empty? # => false
-
1
def empty?
-
88
all? { |k, v| v && v.empty? && !v.is_a?(String) }
-
end
-
# aliases empty?
-
1
alias_method :blank?, :empty?
-
-
# Returns an xml formatted representation of the Errors hash.
-
#
-
# person.errors.add(:name, "can't be blank")
-
# person.errors.add(:name, "must be specified")
-
# person.errors.to_xml
-
# # =>
-
# # <?xml version=\"1.0\" encoding=\"UTF-8\"?>
-
# # <errors>
-
# # <error>name can't be blank</error>
-
# # <error>name must be specified</error>
-
# # </errors>
-
1
def to_xml(options={})
-
to_a.to_xml({ :root => "errors", :skip_types => true }.merge!(options))
-
end
-
-
# Returns a Hash that can be used as the JSON representation for this
-
# object. You can pass the <tt>:full_messages</tt> option. This determines
-
# if the json object should contain full messages or not (false by default).
-
#
-
# person.errors.as_json # => {:name=>["can not be nil"]}
-
# person.errors.as_json(full_messages: true) # => {:name=>["name can not be nil"]}
-
1
def as_json(options=nil)
-
to_hash(options && options[:full_messages])
-
end
-
-
# Returns a Hash of attributes with their error messages. If +full_messages+
-
# is +true+, it will contain full messages (see +full_message+).
-
#
-
# person.errors.to_hash # => {:name=>["can not be nil"]}
-
# person.errors.to_hash(true) # => {:name=>["name can not be nil"]}
-
1
def to_hash(full_messages = false)
-
if full_messages
-
messages = {}
-
self.messages.each do |attribute, array|
-
messages[attribute] = array.map { |message| full_message(attribute, message) }
-
end
-
messages
-
else
-
self.messages.dup
-
end
-
end
-
-
# Adds +message+ to the error messages on +attribute+. More than one error
-
# can be added to the same +attribute+. If no +message+ is supplied,
-
# <tt>:invalid</tt> is assumed.
-
#
-
# person.errors.add(:name)
-
# # => ["is invalid"]
-
# person.errors.add(:name, 'must be implemented')
-
# # => ["is invalid", "must be implemented"]
-
#
-
# person.errors.messages
-
# # => {:name=>["must be implemented", "is invalid"]}
-
#
-
# If +message+ is a symbol, it will be translated using the appropriate
-
# scope (see +generate_message+).
-
#
-
# If +message+ is a proc, it will be called, allowing for things like
-
# <tt>Time.now</tt> to be used within an error.
-
#
-
# If the <tt>:strict</tt> option is set to true will raise
-
# ActiveModel::StrictValidationFailed instead of adding the error.
-
# <tt>:strict</tt> option can also be set to any other exception.
-
#
-
# person.errors.add(:name, nil, strict: true)
-
# # => ActiveModel::StrictValidationFailed: name is invalid
-
# person.errors.add(:name, nil, strict: NameIsInvalid)
-
# # => NameIsInvalid: name is invalid
-
#
-
# person.errors.messages # => {}
-
1
def add(attribute, message = nil, options = {})
-
22
message = normalize_message(attribute, message, options)
-
22
if exception = options[:strict]
-
exception = ActiveModel::StrictValidationFailed if exception == true
-
raise exception, full_message(attribute, message)
-
end
-
-
22
self[attribute] << message
-
end
-
-
# Will add an error message to each of the attributes in +attributes+
-
# that is empty.
-
#
-
# person.errors.add_on_empty(:name)
-
# person.errors.messages
-
# # => {:name=>["can't be empty"]}
-
1
def add_on_empty(attributes, options = {})
-
Array(attributes).each do |attribute|
-
value = @base.send(:read_attribute_for_validation, attribute)
-
is_empty = value.respond_to?(:empty?) ? value.empty? : false
-
add(attribute, :empty, options) if value.nil? || is_empty
-
end
-
end
-
-
# Will add an error message to each of the attributes in +attributes+ that
-
# is blank (using Object#blank?).
-
#
-
# person.errors.add_on_blank(:name)
-
# person.errors.messages
-
# # => {:name=>["can't be blank"]}
-
1
def add_on_blank(attributes, options = {})
-
Array(attributes).each do |attribute|
-
value = @base.send(:read_attribute_for_validation, attribute)
-
add(attribute, :blank, options) if value.blank?
-
end
-
end
-
-
# Returns +true+ if an error on the attribute with the given message is
-
# present, +false+ otherwise. +message+ is treated the same as for +add+.
-
#
-
# person.errors.add :name, :blank
-
# person.errors.added? :name, :blank # => true
-
1
def added?(attribute, message = nil, options = {})
-
message = normalize_message(attribute, message, options)
-
self[attribute].include? message
-
end
-
-
# Returns all the full error messages in an array.
-
#
-
# class Person
-
# validates_presence_of :name, :address, :email
-
# validates_length_of :name, in: 5..30
-
# end
-
#
-
# person = Person.create(address: '123 First St.')
-
# person.errors.full_messages
-
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Email can't be blank"]
-
1
def full_messages
-
map { |attribute, message| full_message(attribute, message) }
-
end
-
-
# Returns all the full error messages for a given attribute in an array.
-
#
-
# class Person
-
# validates_presence_of :name, :email
-
# validates_length_of :name, in: 5..30
-
# end
-
#
-
# person = Person.create()
-
# person.errors.full_messages_for(:name)
-
# # => ["Name is too short (minimum is 5 characters)", "Name can't be blank"]
-
1
def full_messages_for(attribute)
-
(get(attribute) || []).map { |message| full_message(attribute, message) }
-
end
-
-
# Returns a full message for a given attribute.
-
#
-
# person.errors.full_message(:name, 'is invalid') # => "Name is invalid"
-
1
def full_message(attribute, message)
-
return message if attribute == :base
-
attr_name = attribute.to_s.tr('.', '_').humanize
-
attr_name = @base.class.human_attribute_name(attribute, :default => attr_name)
-
I18n.t(:"errors.format", {
-
:default => "%{attribute} %{message}",
-
:attribute => attr_name,
-
:message => message
-
})
-
end
-
-
# Translates an error message in its default scope
-
# (<tt>activemodel.errors.messages</tt>).
-
#
-
# Error messages are first looked up in <tt>models.MODEL.attributes.ATTRIBUTE.MESSAGE</tt>,
-
# if it's not there, it's looked up in <tt>models.MODEL.MESSAGE</tt> and if
-
# that is not there also, it returns the translation of the default message
-
# (e.g. <tt>activemodel.errors.messages.MESSAGE</tt>). The translated model
-
# name, translated attribute name and the value are available for
-
# interpolation.
-
#
-
# When using inheritance in your models, it will check all the inherited
-
# models too, but only if the model itself hasn't been found. Say you have
-
# <tt>class Admin < User; end</tt> and you wanted the translation for
-
# the <tt>:blank</tt> error message for the <tt>title</tt> attribute,
-
# it looks for these translations:
-
#
-
# * <tt>activemodel.errors.models.admin.attributes.title.blank</tt>
-
# * <tt>activemodel.errors.models.admin.blank</tt>
-
# * <tt>activemodel.errors.models.user.attributes.title.blank</tt>
-
# * <tt>activemodel.errors.models.user.blank</tt>
-
# * any default you provided through the +options+ hash (in the <tt>activemodel.errors</tt> scope)
-
# * <tt>activemodel.errors.messages.blank</tt>
-
# * <tt>errors.attributes.title.blank</tt>
-
# * <tt>errors.messages.blank</tt>
-
1
def generate_message(attribute, type = :invalid, options = {})
-
52
type = options.delete(:message) if options[:message].is_a?(Symbol)
-
-
52
if @base.class.respond_to?(:i18n_scope)
-
52
defaults = @base.class.lookup_ancestors.map do |klass|
-
52
[ :"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.attributes.#{attribute}.#{type}",
-
:"#{@base.class.i18n_scope}.errors.models.#{klass.model_name.i18n_key}.#{type}" ]
-
end
-
else
-
defaults = []
-
end
-
-
52
defaults << options.delete(:message)
-
52
defaults << :"#{@base.class.i18n_scope}.errors.messages.#{type}" if @base.class.respond_to?(:i18n_scope)
-
52
defaults << :"errors.attributes.#{attribute}.#{type}"
-
52
defaults << :"errors.messages.#{type}"
-
-
52
defaults.compact!
-
52
defaults.flatten!
-
-
52
key = defaults.shift
-
52
value = (attribute != :base ? @base.send(:read_attribute_for_validation, attribute) : nil)
-
-
52
options = {
-
:default => defaults,
-
:model => @base.class.model_name.human,
-
:attribute => @base.class.human_attribute_name(attribute),
-
:value => value
-
}.merge!(options)
-
-
52
I18n.translate(key, options)
-
end
-
-
1
private
-
1
def normalize_message(attribute, message, options)
-
22
message ||= :invalid
-
-
22
case message
-
when Symbol
-
22
generate_message(attribute, message, options.except(*CALLBACKS_OPTIONS))
-
when Proc
-
message.call
-
else
-
message
-
end
-
end
-
end
-
-
# Raised when a validation cannot be corrected by end users and are considered
-
# exceptional.
-
#
-
# class Person
-
# include ActiveModel::Validations
-
#
-
# attr_accessor :name
-
#
-
# validates_presence_of :name, strict: true
-
# end
-
#
-
# person = Person.new
-
# person.name = nil
-
# person.valid?
-
# # => ActiveModel::StrictValidationFailed: Name can't be blank
-
1
class StrictValidationFailed < StandardError
-
end
-
end
-
1
module ActiveRecord
-
1
class AssociationRelation < Relation
-
1
def initialize(klass, table, association)
-
16
super(klass, table)
-
16
@association = association
-
end
-
-
1
def proxy_association
-
@association
-
end
-
-
1
private
-
-
1
def exec_queries
-
8
super.each { |r| @association.set_inverse_instance r }
-
end
-
end
-
end
-
1
require 'active_support/core_ext/string/conversions'
-
-
1
module ActiveRecord
-
1
module Associations
-
# Keeps track of table aliases for ActiveRecord::Associations::ClassMethods::JoinDependency and
-
# ActiveRecord::Associations::ThroughAssociationScope
-
1
class AliasTracker # :nodoc:
-
1
attr_reader :aliases, :table_joins, :connection
-
-
# table_joins is an array of arel joins which might conflict with the aliases we assign here
-
1
def initialize(connection = Base.connection, table_joins = [])
-
24
@aliases = Hash.new { |h,k| h[k] = initial_count_for(k) }
-
12
@table_joins = table_joins
-
12
@connection = connection
-
end
-
-
1
def aliased_table_for(table_name, aliased_name = nil)
-
12
table_alias = aliased_name_for(table_name, aliased_name)
-
-
12
if table_alias == table_name
-
12
Arel::Table.new(table_name)
-
else
-
Arel::Table.new(table_name).alias(table_alias)
-
end
-
end
-
-
1
def aliased_name_for(table_name, aliased_name = nil)
-
12
aliased_name ||= table_name
-
-
12
if aliases[table_name].zero?
-
# If it's zero, we can have our table_name
-
12
aliases[table_name] = 1
-
12
table_name
-
else
-
# Otherwise, we need to use an alias
-
aliased_name = connection.table_alias_for(aliased_name)
-
-
# Update the count
-
aliases[aliased_name] += 1
-
-
if aliases[aliased_name] > 1
-
"#{truncate(aliased_name)}_#{aliases[aliased_name]}"
-
else
-
aliased_name
-
end
-
end
-
end
-
-
1
private
-
-
1
def initial_count_for(name)
-
12
return 0 if Arel::Table === table_joins
-
-
# quoted_name should be downcased as some database adapters (Oracle) return quoted name in uppercase
-
12
quoted_name = connection.quote_table_name(name).downcase
-
-
12
counts = table_joins.map do |join|
-
if join.is_a?(Arel::Nodes::StringJoin)
-
# Table names + table aliases
-
join.left.downcase.scan(
-
/join(?:\s+\w+)?\s+(\S+\s+)?#{quoted_name}\son/
-
).size
-
else
-
join.left.table_name == name ? 1 : 0
-
end
-
end
-
-
12
counts.sum
-
end
-
-
1
def truncate(name)
-
name.slice(0, connection.table_alias_length - 2)
-
end
-
end
-
end
-
end
-
1
require 'active_support/core_ext/array/wrap'
-
-
1
module ActiveRecord
-
1
module Associations
-
# = Active Record Associations
-
#
-
# This is the root class of all associations ('+ Foo' signifies an included module Foo):
-
#
-
# Association
-
# SingularAssociation
-
# HasOneAssociation
-
# HasOneThroughAssociation + ThroughAssociation
-
# BelongsToAssociation
-
# BelongsToPolymorphicAssociation
-
# CollectionAssociation
-
# HasAndBelongsToManyAssociation
-
# HasManyAssociation
-
# HasManyThroughAssociation + ThroughAssociation
-
1
class Association #:nodoc:
-
1
attr_reader :owner, :target, :reflection
-
1
attr_accessor :inversed
-
-
1
delegate :options, :to => :reflection
-
-
1
def initialize(owner, reflection)
-
12
reflection.check_validity!
-
-
12
@owner, @reflection = owner, reflection
-
-
12
reset
-
12
reset_scope
-
end
-
-
# Returns the name of the table of the associated class:
-
#
-
# post.comments.aliased_table_name # => "comments"
-
#
-
1
def aliased_table_name
-
klass.table_name
-
end
-
-
# Resets the \loaded flag to +false+ and sets the \target to +nil+.
-
1
def reset
-
20
@loaded = false
-
20
@target = nil
-
20
@stale_state = nil
-
20
@inversed = false
-
end
-
-
# Reloads the \target and returns +self+ on success.
-
1
def reload
-
reset
-
reset_scope
-
load_target
-
self unless target.nil?
-
end
-
-
# Has the \target been already \loaded?
-
1
def loaded?
-
20
@loaded
-
end
-
-
# Asserts the \target has been loaded setting the \loaded flag to +true+.
-
1
def loaded!
-
24
@loaded = true
-
24
@stale_state = stale_state
-
24
@inversed = false
-
end
-
-
# The target is stale if the target no longer points to the record(s) that the
-
# relevant foreign_key(s) refers to. If stale, the association accessor method
-
# on the owner will reload the target. It's up to subclasses to implement the
-
# state_state method if relevant.
-
#
-
# Note that if the target has not been loaded, it is not considered stale.
-
1
def stale_target?
-
4
!inversed && loaded? && @stale_state != stale_state
-
end
-
-
# Sets the target of this association to <tt>\target</tt>, and the \loaded flag to +true+.
-
1
def target=(target)
-
@target = target
-
loaded!
-
end
-
-
1
def scope
-
16
target_scope.merge(association_scope)
-
end
-
-
1
def scoped
-
ActiveSupport::Deprecation.warn "#scoped is deprecated. use #scope instead."
-
scope
-
end
-
-
# The scope for this association.
-
#
-
# Note that the association_scope is merged into the target_scope only when the
-
# scope method is called. This is because at that point the call may be surrounded
-
# by scope.scoping { ... } or with_scope { ... } etc, which affects the scope which
-
# actually gets built.
-
1
def association_scope
-
20
if klass
-
20
@association_scope ||= AssociationScope.new(self).scope
-
end
-
end
-
-
1
def reset_scope
-
12
@association_scope = nil
-
end
-
-
# Set the inverse association, if possible
-
1
def set_inverse_instance(record)
-
8
if record && invertible_for?(record)
-
inverse = record.association(inverse_reflection_for(record).name)
-
inverse.target = owner
-
inverse.inversed = true
-
end
-
end
-
-
# Returns the class of the target. belongs_to polymorphic overrides this to look at the
-
# polymorphic_type field on the owner.
-
1
def klass
-
116
reflection.klass
-
end
-
-
# Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
-
# through association's scope)
-
1
def target_scope
-
16
all = klass.all
-
16
scope = AssociationRelation.new(klass, klass.arel_table, self)
-
16
scope.merge! all
-
16
scope.default_scoped = all.default_scoped?
-
16
scope
-
end
-
-
# Loads the \target if needed and returns it.
-
#
-
# This method is abstract in the sense that it relies on +find_target+,
-
# which is expected to be provided by descendants.
-
#
-
# If the \target is already \loaded it is just returned. Thus, you can call
-
# +load_target+ unconditionally to get the \target.
-
#
-
# ActiveRecord::RecordNotFound is rescued within the method, and it is
-
# not reraised. The proxy is \reset and +nil+ is the return value.
-
1
def load_target
-
@target = find_target if (@stale_state && stale_target?) || find_target?
-
-
loaded! unless loaded?
-
target
-
rescue ActiveRecord::RecordNotFound
-
reset
-
end
-
-
1
def interpolate(sql, record = nil)
-
if sql.respond_to?(:to_proc)
-
owner.instance_exec(record, &sql)
-
else
-
sql
-
end
-
end
-
-
# We can't dump @reflection since it contains the scope proc
-
1
def marshal_dump
-
ivars = (instance_variables - [:@reflection]).map { |name| [name, instance_variable_get(name)] }
-
[@reflection.name, ivars]
-
end
-
-
1
def marshal_load(data)
-
reflection_name, ivars = data
-
ivars.each { |name, val| instance_variable_set(name, val) }
-
@reflection = @owner.class.reflect_on_association(reflection_name)
-
end
-
-
1
def initialize_attributes(record) #:nodoc:
-
4
skip_assign = [reflection.foreign_key, reflection.type].compact
-
4
attributes = create_scope.except(*(record.changed - skip_assign))
-
4
record.assign_attributes(attributes)
-
4
set_inverse_instance(record)
-
end
-
-
1
private
-
-
1
def find_target?
-
16
!loaded? && (!owner.new_record? || foreign_key_present?) && klass
-
end
-
-
1
def creation_attributes
-
attributes = {}
-
-
if (reflection.macro == :has_one || reflection.macro == :has_many) && !options[:through]
-
attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]
-
-
if reflection.options[:as]
-
attributes[reflection.type] = owner.class.base_class.name
-
end
-
end
-
-
attributes
-
end
-
-
# Sets the owner attributes on the given record
-
1
def set_owner_attributes(record)
-
creation_attributes.each { |key, value| record[key] = value }
-
end
-
-
# Should be true if there is a foreign key present on the owner which
-
# references the target. This is used to determine whether we can load
-
# the target if the owner is currently a new record (and therefore
-
# without a key).
-
#
-
# Currently implemented by belongs_to (vanilla and polymorphic) and
-
# has_one/has_many :through associations which go through a belongs_to
-
1
def foreign_key_present?
-
false
-
end
-
-
# Raises ActiveRecord::AssociationTypeMismatch unless +record+ is of
-
# the kind of the class of the associated objects. Meant to be used as
-
# a sanity check when you are about to assign an associated record.
-
1
def raise_on_type_mismatch!(record)
-
unless record.is_a?(reflection.klass) || record.is_a?(reflection.class_name.constantize)
-
message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
-
raise ActiveRecord::AssociationTypeMismatch, message
-
end
-
end
-
-
# Can be redefined by subclasses, notably polymorphic belongs_to
-
# The record parameter is necessary to support polymorphic inverses as we must check for
-
# the association in the specific class of the record.
-
1
def inverse_reflection_for(record)
-
8
reflection.inverse_of
-
end
-
-
# Returns true if inverse association on the given record needs to be set.
-
# This method is redefined by subclasses.
-
1
def invertible_for?(record)
-
8
inverse_reflection_for(record)
-
end
-
-
# This should be implemented to return the values of the relevant key(s) on the owner,
-
# so that when stale_state is different from the value stored on the last find_target,
-
# the target is stale.
-
#
-
# This is only relevant to certain associations, which is why it returns nil by default.
-
1
def stale_state
-
end
-
-
1
def build_record(attributes)
-
4
reflection.build_association(attributes) do |record|
-
4
initialize_attributes(record)
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
1
class AssociationScope #:nodoc:
-
1
include JoinHelper
-
-
1
attr_reader :association, :alias_tracker
-
-
1
delegate :klass, :owner, :reflection, :interpolate, :to => :association
-
1
delegate :chain, :scope_chain, :options, :source_options, :active_record, :to => :reflection
-
-
1
def initialize(association)
-
12
@association = association
-
12
@alias_tracker = AliasTracker.new klass.connection
-
end
-
-
1
def scope
-
12
scope = klass.unscoped
-
12
scope.extending! Array(options[:extend])
-
12
add_constraints(scope)
-
end
-
-
1
private
-
-
1
def column_for(table_name, column_name)
-
12
columns = alias_tracker.connection.schema_cache.columns_hash(table_name)
-
12
columns[column_name]
-
end
-
-
1
def bind_value(scope, column, value)
-
12
substitute = alias_tracker.connection.substitute_at(
-
column, scope.bind_values.length)
-
12
scope.bind_values += [[column, value]]
-
12
substitute
-
end
-
-
1
def bind(scope, table_name, column_name, value)
-
12
column = column_for table_name, column_name
-
12
bind_value scope, column, value
-
end
-
-
1
def add_constraints(scope)
-
12
tables = construct_tables
-
-
12
chain.each_with_index do |reflection, i|
-
12
table, foreign_table = tables.shift, tables.first
-
-
12
if reflection.source_macro == :has_and_belongs_to_many
-
join_table = tables.shift
-
-
scope = scope.joins(join(
-
join_table,
-
table[reflection.association_primary_key].
-
eq(join_table[reflection.association_foreign_key])
-
))
-
-
table, foreign_table = join_table, tables.first
-
end
-
-
12
if reflection.source_macro == :belongs_to
-
if reflection.options[:polymorphic]
-
key = reflection.association_primary_key(self.klass)
-
else
-
key = reflection.association_primary_key
-
end
-
-
foreign_key = reflection.foreign_key
-
else
-
12
key = reflection.foreign_key
-
12
foreign_key = reflection.active_record_primary_key
-
end
-
-
12
if reflection == chain.last
-
12
bind_val = bind scope, table.table_name, key.to_s, owner[foreign_key]
-
12
scope = scope.where(table[key].eq(bind_val))
-
-
12
if reflection.type
-
value = owner.class.base_class.name
-
bind_val = bind scope, table.table_name, reflection.type.to_s, value
-
scope = scope.where(table[reflection.type].eq(bind_val))
-
end
-
else
-
constraint = table[key].eq(foreign_table[foreign_key])
-
-
if reflection.type
-
type = chain[i + 1].klass.base_class.name
-
constraint = constraint.and(table[reflection.type].eq(type))
-
end
-
-
scope = scope.joins(join(foreign_table, constraint))
-
end
-
-
# Exclude the scope of the association itself, because that
-
# was already merged in the #scope method.
-
12
scope_chain[i].each do |scope_chain_item|
-
klass = i == 0 ? self.klass : reflection.klass
-
item = eval_scope(klass, scope_chain_item)
-
-
if scope_chain_item == self.reflection.scope
-
scope.merge! item.except(:where, :includes)
-
end
-
-
scope.includes! item.includes_values
-
scope.where_values += item.where_values
-
scope.order_values |= item.order_values
-
end
-
end
-
-
12
scope
-
end
-
-
1
def alias_suffix
-
12
reflection.name
-
end
-
-
1
def table_name_for(reflection)
-
12
if reflection == self.reflection
-
# If this is a polymorphic belongs_to, we want to get the klass from the
-
# association because it depends on the polymorphic_type attribute of
-
# the owner
-
12
klass.table_name
-
else
-
reflection.table_name
-
end
-
end
-
-
1
def eval_scope(klass, scope)
-
if scope.is_a?(Relation)
-
scope
-
else
-
klass.unscoped.instance_exec(owner, &scope)
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord::Associations::Builder
-
1
class HasMany < CollectionAssociation #:nodoc:
-
1
def macro
-
12
:has_many
-
end
-
-
1
def valid_options
-
4
super + [:primary_key, :dependent, :as, :through, :source, :source_type, :inverse_of, :counter_cache]
-
end
-
-
1
def valid_dependent_options
-
4
[:destroy, :delete_all, :nullify, :restrict, :restrict_with_error, :restrict_with_exception]
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
# = Active Record Association Collection
-
#
-
# CollectionAssociation is an abstract class that provides common stuff to
-
# ease the implementation of association proxies that represent
-
# collections. See the class hierarchy in AssociationProxy.
-
#
-
# CollectionAssociation:
-
# HasAndBelongsToManyAssociation => has_and_belongs_to_many
-
# HasManyAssociation => has_many
-
# HasManyThroughAssociation + ThroughAssociation => has_many :through
-
#
-
# CollectionAssociation class provides common methods to the collections
-
# defined by +has_and_belongs_to_many+, +has_many+ or +has_many+ with
-
# +:through association+ option.
-
#
-
# You need to be careful with assumptions regarding the target: The proxy
-
# does not fetch records from the database until it needs them, but new
-
# ones created with +build+ are added to the target. So, the target may be
-
# non-empty and still lack children waiting to be read from the database.
-
# If you look directly to the database you cannot assume that's the entire
-
# collection because new records may have been added to the target, etc.
-
#
-
# If you need to work on all current children, new and existing records,
-
# +load_target+ and the +loaded+ flag are your friends.
-
1
class CollectionAssociation < Association #:nodoc:
-
-
# Implements the reader method, e.g. foo.items for Foo.has_many :items
-
1
def reader(force_reload = false)
-
4
if force_reload
-
klass.uncached { reload }
-
elsif stale_target?
-
reload
-
end
-
-
4
@proxy ||= CollectionProxy.new(klass, self)
-
end
-
-
# Implements the writer method, e.g. foo.items= for Foo.has_many :items
-
1
def writer(records)
-
replace(records)
-
end
-
-
# Implements the ids reader method, e.g. foo.item_ids for Foo.has_many :items
-
1
def ids_reader
-
if loaded? || options[:finder_sql]
-
load_target.map do |record|
-
record.send(reflection.association_primary_key)
-
end
-
else
-
column = "#{reflection.quoted_table_name}.#{reflection.association_primary_key}"
-
scope.pluck(column)
-
end
-
end
-
-
# Implements the ids writer method, e.g. foo.item_ids= for Foo.has_many :items
-
1
def ids_writer(ids)
-
pk_column = reflection.primary_key_column
-
ids = Array(ids).reject { |id| id.blank? }
-
ids.map! { |i| pk_column.type_cast(i) }
-
replace(klass.find(ids).index_by { |r| r.id }.values_at(*ids))
-
end
-
-
1
def reset
-
20
super
-
20
@target = []
-
end
-
-
1
def select(select = nil)
-
if block_given?
-
load_target.select.each { |e| yield e }
-
else
-
scope.select(select)
-
end
-
end
-
-
1
def find(*args)
-
if block_given?
-
load_target.find(*args) { |*block_args| yield(*block_args) }
-
else
-
if options[:finder_sql]
-
find_by_scan(*args)
-
elsif options[:inverse_of] && loaded?
-
args_flatten = args.flatten
-
raise RecordNotFound, "Couldn't find #{scope.klass.name} without an ID" if args_flatten.blank?
-
-
result = find_by_scan(*args)
-
-
result_size = Array(result).size
-
if !result || result_size != args_flatten.size
-
scope.raise_record_not_found_exception!(args_flatten, result_size, args_flatten.size)
-
else
-
result
-
end
-
else
-
scope.find(*args)
-
end
-
end
-
end
-
-
1
def first(*args)
-
first_or_last(:first, *args)
-
end
-
-
1
def last(*args)
-
first_or_last(:last, *args)
-
end
-
-
1
def build(attributes = {}, &block)
-
4
if attributes.is_a?(Array)
-
attributes.collect { |attr| build(attr, &block) }
-
else
-
4
add_to_target(build_record(attributes)) do |record|
-
4
yield(record) if block_given?
-
end
-
end
-
end
-
-
1
def create(attributes = {}, &block)
-
create_record(attributes, &block)
-
end
-
-
1
def create!(attributes = {}, &block)
-
create_record(attributes, true, &block)
-
end
-
-
# Add +records+ to this association. Returns +self+ so method calls may
-
# be chained. Since << flattens its argument list and inserts each record,
-
# +push+ and +concat+ behave identically.
-
1
def concat(*records)
-
load_target if owner.new_record?
-
-
if owner.new_record?
-
concat_records(records)
-
else
-
transaction { concat_records(records) }
-
end
-
end
-
-
# Starts a transaction in the association class's database connection.
-
#
-
# class Author < ActiveRecord::Base
-
# has_many :books
-
# end
-
#
-
# Author.first.books.transaction do
-
# # same effect as calling Book.transaction
-
# end
-
1
def transaction(*args)
-
reflection.klass.transaction(*args) do
-
yield
-
end
-
end
-
-
# Remove all records from this association.
-
#
-
# See delete for more info.
-
1
def delete_all
-
delete(:all).tap do
-
reset
-
loaded!
-
end
-
end
-
-
# Destroy all the records from this association.
-
#
-
# See destroy for more info.
-
1
def destroy_all
-
8
destroy(load_target).tap do
-
8
reset
-
8
loaded!
-
end
-
end
-
-
# Count all records using SQL. If the +:counter_sql+ or +:finder_sql+ option is set for the
-
# association, it will be used for the query. Otherwise, construct options and pass them with
-
# scope to the target class's +count+.
-
1
def count(column_name = nil, count_options = {})
-
column_name, count_options = nil, column_name if column_name.is_a?(Hash)
-
-
if options[:counter_sql] || options[:finder_sql]
-
unless count_options.blank?
-
raise ArgumentError, "If finder_sql/counter_sql is used then options cannot be passed"
-
end
-
-
reflection.klass.count_by_sql(custom_counter_sql)
-
else
-
relation = scope
-
if association_scope.distinct_value
-
# This is needed because 'SELECT count(DISTINCT *)..' is not valid SQL.
-
column_name ||= reflection.klass.primary_key
-
relation = relation.distinct
-
end
-
-
value = relation.count(column_name)
-
-
limit = options[:limit]
-
offset = options[:offset]
-
-
if limit || offset
-
[ [value - offset.to_i, 0].max, limit.to_i ].min
-
else
-
value
-
end
-
end
-
end
-
-
# Removes +records+ from this association calling +before_remove+ and
-
# +after_remove+ callbacks.
-
#
-
# This method is abstract in the sense that +delete_records+ has to be
-
# provided by descendants. Note this method does not imply the records
-
# are actually removed from the database, that depends precisely on
-
# +delete_records+. They are in any case removed from the collection.
-
1
def delete(*records)
-
dependent = options[:dependent]
-
-
if records.first == :all
-
-
if dependent && dependent == :destroy
-
message = 'In Rails 4.1 delete_all on associations would not fire callbacks. ' \
-
'It means if the :dependent option is :destroy then the associated ' \
-
'records would be deleted without loading and invoking callbacks.'
-
-
ActiveRecord::Base.logger ? ActiveRecord::Base.logger.warn(message) : $stderr.puts(message)
-
end
-
-
if loaded? || dependent == :destroy
-
delete_or_destroy(load_target, dependent)
-
else
-
delete_records(:all, dependent)
-
end
-
else
-
records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
-
delete_or_destroy(records, dependent)
-
end
-
end
-
-
# Destroy +records+ and remove them from this association calling
-
# +before_remove+ and +after_remove+ callbacks.
-
#
-
# Note that this method will _always_ remove records from the database
-
# ignoring the +:dependent+ option.
-
1
def destroy(*records)
-
16
records = find(records) if records.any? { |record| record.kind_of?(Fixnum) || record.kind_of?(String) }
-
8
delete_or_destroy(records, :destroy)
-
end
-
-
# Returns the size of the collection by executing a SELECT COUNT(*)
-
# query if the collection hasn't been loaded, and calling
-
# <tt>collection.size</tt> if it has.
-
#
-
# If the collection has been already loaded +size+ and +length+ are
-
# equivalent. If not and you are going to need the records anyway
-
# +length+ will take one less query. Otherwise +size+ is more efficient.
-
#
-
# This method is abstract in the sense that it relies on
-
# +count_records+, which is a method descendants have to provide.
-
1
def size
-
if !find_target? || loaded?
-
if association_scope.distinct_value
-
target.uniq.size
-
else
-
target.size
-
end
-
elsif !loaded? && !association_scope.group_values.empty?
-
load_target.size
-
elsif !loaded? && !association_scope.distinct_value && target.is_a?(Array)
-
unsaved_records = target.select { |r| r.new_record? }
-
unsaved_records.size + count_records
-
else
-
count_records
-
end
-
end
-
-
# Returns the size of the collection calling +size+ on the target.
-
#
-
# If the collection has been already loaded +length+ and +size+ are
-
# equivalent. If not and you are going to need the records anyway this
-
# method will take one less query. Otherwise +size+ is more efficient.
-
1
def length
-
load_target.size
-
end
-
-
# Returns true if the collection is empty.
-
#
-
# If the collection has been loaded or the <tt>:counter_sql</tt> option
-
# is provided, it is equivalent to <tt>collection.size.zero?</tt>. If the
-
# collection has not been loaded, it is equivalent to
-
# <tt>collection.exists?</tt>. If the collection has not already been
-
# loaded and you are going to fetch the records anyway it is better to
-
# check <tt>collection.length.zero?</tt>.
-
1
def empty?
-
if loaded? || options[:counter_sql]
-
size.zero?
-
else
-
@target.blank? && !scope.exists?
-
end
-
end
-
-
# Returns true if the collections is not empty.
-
# Equivalent to +!collection.empty?+.
-
1
def any?
-
if block_given?
-
load_target.any? { |*block_args| yield(*block_args) }
-
else
-
!empty?
-
end
-
end
-
-
# Returns true if the collection has more than 1 record.
-
# Equivalent to +collection.size > 1+.
-
1
def many?
-
if block_given?
-
load_target.many? { |*block_args| yield(*block_args) }
-
else
-
size > 1
-
end
-
end
-
-
1
def distinct
-
seen = {}
-
load_target.find_all do |record|
-
seen[record.id] = true unless seen.key?(record.id)
-
end
-
end
-
1
alias uniq distinct
-
-
# Replace this collection with +other_array+. This will perform a diff
-
# and delete/add only records that have changed.
-
1
def replace(other_array)
-
other_array.each { |val| raise_on_type_mismatch!(val) }
-
original_target = load_target.dup
-
-
if owner.new_record?
-
replace_records(other_array, original_target)
-
else
-
transaction { replace_records(other_array, original_target) }
-
end
-
end
-
-
1
def include?(record)
-
if record.is_a?(reflection.klass)
-
if record.new_record?
-
include_in_memory?(record)
-
else
-
load_target if options[:finder_sql]
-
loaded? ? target.include?(record) : scope.exists?(record)
-
end
-
else
-
false
-
end
-
end
-
-
1
def load_target
-
16
if find_target?
-
8
@target = merge_target_lists(find_target, target)
-
end
-
-
16
loaded!
-
16
target
-
end
-
-
1
def add_to_target(record)
-
4
callback(:before_add, record)
-
4
yield(record) if block_given?
-
-
4
if association_scope.distinct_value && index = @target.index(record)
-
@target[index] = record
-
else
-
4
@target << record
-
end
-
-
4
callback(:after_add, record)
-
4
set_inverse_instance(record)
-
-
4
record
-
end
-
-
1
def scope(opts = {})
-
16
scope = super()
-
16
scope.none! if opts.fetch(:nullify, true) && null_scope?
-
16
scope
-
end
-
-
1
def null_scope?
-
12
owner.new_record? && !foreign_key_present?
-
end
-
-
1
private
-
-
1
def custom_counter_sql
-
if options[:counter_sql]
-
interpolate(options[:counter_sql])
-
else
-
# replace the SELECT clause with COUNT(SELECTS), preserving any hints within /* ... */
-
interpolate(options[:finder_sql]).sub(/SELECT\b(\/\*.*?\*\/ )?(.*)\bFROM\b/im) do
-
count_with = $2.to_s
-
count_with = '*' if count_with.blank? || count_with =~ /,/ || count_with =~ /\.\*/
-
"SELECT #{$1}COUNT(#{count_with}) FROM"
-
end
-
end
-
end
-
-
1
def custom_finder_sql
-
interpolate(options[:finder_sql])
-
end
-
-
1
def find_target
-
8
records =
-
if options[:finder_sql]
-
reflection.klass.find_by_sql(custom_finder_sql)
-
else
-
8
scope.to_a
-
end
-
-
8
records.each { |record| set_inverse_instance(record) }
-
8
records
-
end
-
-
# We have some records loaded from the database (persisted) and some that are
-
# in-memory (memory). The same record may be represented in the persisted array
-
# and in the memory array.
-
#
-
# So the task of this method is to merge them according to the following rules:
-
#
-
# * The final array must not have duplicates
-
# * The order of the persisted array is to be preserved
-
# * Any changes made to attributes on objects in the memory array are to be preserved
-
# * Otherwise, attributes should have the value found in the database
-
1
def merge_target_lists(persisted, memory)
-
8
return persisted if memory.empty?
-
return memory if persisted.empty?
-
-
persisted.map! do |record|
-
if mem_record = memory.delete(record)
-
-
((record.attribute_names & mem_record.attribute_names) - mem_record.changes.keys).each do |name|
-
mem_record[name] = record[name]
-
end
-
-
mem_record
-
else
-
record
-
end
-
end
-
-
persisted + memory
-
end
-
-
1
def create_record(attributes, raise = false, &block)
-
unless owner.persisted?
-
raise ActiveRecord::RecordNotSaved, "You cannot call create unless the parent is saved"
-
end
-
-
if attributes.is_a?(Array)
-
attributes.collect { |attr| create_record(attr, raise, &block) }
-
else
-
transaction do
-
add_to_target(build_record(attributes)) do |record|
-
yield(record) if block_given?
-
insert_record(record, true, raise)
-
end
-
end
-
end
-
end
-
-
# Do the relevant stuff to insert the given record into the association collection.
-
1
def insert_record(record, validate = true, raise = false)
-
raise NotImplementedError
-
end
-
-
1
def create_scope
-
4
scope.scope_for_create.stringify_keys
-
end
-
-
1
def delete_or_destroy(records, method)
-
8
records = records.flatten
-
8
records.each { |record| raise_on_type_mismatch!(record) }
-
8
existing_records = records.reject { |r| r.new_record? }
-
-
8
if existing_records.empty?
-
8
remove_records(existing_records, records, method)
-
else
-
transaction { remove_records(existing_records, records, method) }
-
end
-
end
-
-
1
def remove_records(existing_records, records, method)
-
8
records.each { |record| callback(:before_remove, record) }
-
-
8
delete_records(existing_records, method) if existing_records.any?
-
8
records.each { |record| target.delete(record) }
-
-
8
records.each { |record| callback(:after_remove, record) }
-
end
-
-
# Delete the given records from the association, using one of the methods :destroy,
-
# :delete_all or :nullify (or nil, in which case a default is used).
-
1
def delete_records(records, method)
-
raise NotImplementedError
-
end
-
-
1
def replace_records(new_target, original_target)
-
delete(target - new_target)
-
-
unless concat(new_target - target)
-
@target = original_target
-
raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
-
"new records could not be saved."
-
end
-
-
target
-
end
-
-
1
def concat_records(records)
-
result = true
-
-
records.flatten.each do |record|
-
raise_on_type_mismatch!(record)
-
add_to_target(record) do |rec|
-
result &&= insert_record(rec) unless owner.new_record?
-
end
-
end
-
-
result && records
-
end
-
-
1
def callback(method, record)
-
8
callbacks_for(method).each do |callback|
-
case callback
-
when Symbol
-
owner.send(callback, record)
-
when Proc
-
callback.call(owner, record)
-
else
-
callback.send(method, owner, record)
-
end
-
end
-
end
-
-
1
def callbacks_for(callback_name)
-
8
full_callback_name = "#{callback_name}_for_#{reflection.name}"
-
8
owner.class.send(full_callback_name.to_sym) || []
-
end
-
-
# Should we deal with assoc.first or assoc.last by issuing an independent query to
-
# the database, or by getting the target, and then taking the first/last item from that?
-
#
-
# If the args is just a non-empty options hash, go to the database.
-
#
-
# Otherwise, go to the database only if none of the following are true:
-
# * target already loaded
-
# * owner is new record
-
# * custom :finder_sql exists
-
# * target contains new or changed record(s)
-
# * the first arg is an integer (which indicates the number of records to be returned)
-
1
def fetch_first_or_last_using_find?(args)
-
if args.first.is_a?(Hash)
-
true
-
else
-
!(loaded? ||
-
owner.new_record? ||
-
options[:finder_sql] ||
-
target.any? { |record| record.new_record? || record.changed? } ||
-
args.first.kind_of?(Integer))
-
end
-
end
-
-
1
def include_in_memory?(record)
-
if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
-
owner.send(reflection.through_reflection.name).any? { |source|
-
target = source.send(reflection.source_reflection.name)
-
target.respond_to?(:include?) ? target.include?(record) : target == record
-
} || target.include?(record)
-
else
-
target.include?(record)
-
end
-
end
-
-
# If using a custom finder_sql or if the :inverse_of option has been
-
# specified, then #find scans the entire collection.
-
1
def find_by_scan(*args)
-
expects_array = args.first.kind_of?(Array)
-
ids = args.flatten.compact.map{ |arg| arg.to_s }.uniq
-
-
if ids.size == 1
-
id = ids.first
-
record = load_target.detect { |r| id == r.id.to_s }
-
expects_array ? [ record ] : record
-
else
-
load_target.select { |r| ids.include?(r.id.to_s) }
-
end
-
end
-
-
# Fetches the first/last using SQL if possible, otherwise from the target array.
-
1
def first_or_last(type, *args)
-
args.shift if args.first.is_a?(Hash) && args.first.empty?
-
-
collection = fetch_first_or_last_using_find?(args) ? scope : load_target
-
collection.send(type, *args).tap do |record|
-
set_inverse_instance record if record.is_a? ActiveRecord::Base
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
# = Active Record Has Many Association
-
1
module Associations
-
# This is the proxy that handles a has many association.
-
#
-
# If the association has a <tt>:through</tt> option further specialization
-
# is provided by its child HasManyThroughAssociation.
-
1
class HasManyAssociation < CollectionAssociation #:nodoc:
-
-
1
def handle_dependency
-
8
case options[:dependent]
-
when :restrict, :restrict_with_exception
-
raise ActiveRecord::DeleteRestrictionError.new(reflection.name) unless empty?
-
-
when :restrict_with_error
-
unless empty?
-
record = klass.human_attribute_name(reflection.name).downcase
-
owner.errors.add(:base, :"restrict_dependent_destroy.many", record: record)
-
false
-
end
-
-
else
-
8
if options[:dependent] == :destroy
-
# No point in executing the counter update since we're going to destroy the parent anyway
-
8
load_target.each { |t| t.destroyed_by_association = reflection }
-
8
destroy_all
-
else
-
delete_all
-
end
-
end
-
end
-
-
1
def insert_record(record, validate = true, raise = false)
-
set_owner_attributes(record)
-
set_inverse_instance(record)
-
-
if raise
-
record.save!(:validate => validate)
-
else
-
record.save(:validate => validate)
-
end
-
end
-
-
1
private
-
-
# Returns the number of records in this collection.
-
#
-
# If the association has a counter cache it gets that value. Otherwise
-
# it will attempt to do a count via SQL, bounded to <tt>:limit</tt> if
-
# there's one. Some configuration options like :group make it impossible
-
# to do an SQL count, in those cases the array count will be used.
-
#
-
# That does not depend on whether the collection has already been loaded
-
# or not. The +size+ method is the one that takes the loaded flag into
-
# account and delegates to +count_records+ if needed.
-
#
-
# If the collection is empty the target is set to an empty array and
-
# the loaded flag is set to true as well.
-
1
def count_records
-
count = if has_cached_counter?
-
owner.send(:read_attribute, cached_counter_attribute_name)
-
elsif options[:counter_sql] || options[:finder_sql]
-
reflection.klass.count_by_sql(custom_counter_sql)
-
else
-
scope.count
-
end
-
-
# If there's nothing in the database and @target has no new records
-
# we are certain the current target is an empty array. This is a
-
# documented side-effect of the method that may avoid an extra SELECT.
-
@target ||= [] and loaded! if count == 0
-
-
[association_scope.limit_value, count].compact.min
-
end
-
-
1
def has_cached_counter?(reflection = reflection)
-
owner.attribute_present?(cached_counter_attribute_name(reflection))
-
end
-
-
1
def cached_counter_attribute_name(reflection = reflection)
-
options[:counter_cache] || "#{reflection.name}_count"
-
end
-
-
1
def update_counter(difference, reflection = reflection)
-
if has_cached_counter?(reflection)
-
counter = cached_counter_attribute_name(reflection)
-
owner.class.update_counters(owner.id, counter => difference)
-
owner[counter] += difference
-
owner.changed_attributes.delete(counter) # eww
-
end
-
end
-
-
# This shit is nasty. We need to avoid the following situation:
-
#
-
# * An associated record is deleted via record.destroy
-
# * Hence the callbacks run, and they find a belongs_to on the record with a
-
# :counter_cache options which points back at our owner. So they update the
-
# counter cache.
-
# * In which case, we must make sure to *not* update the counter cache, or else
-
# it will be decremented twice.
-
#
-
# Hence this method.
-
1
def inverse_updates_counter_cache?(reflection = reflection)
-
counter_name = cached_counter_attribute_name(reflection)
-
reflection.klass.reflect_on_all_associations(:belongs_to).any? { |inverse_reflection|
-
inverse_reflection.counter_cache_column == counter_name
-
}
-
end
-
-
# Deletes the records according to the <tt>:dependent</tt> option.
-
1
def delete_records(records, method)
-
if method == :destroy
-
records.each { |r| r.destroy }
-
update_counter(-records.length) unless inverse_updates_counter_cache?
-
else
-
if records == :all
-
scope = self.scope
-
else
-
scope = self.scope.where(reflection.klass.primary_key => records)
-
end
-
-
if method == :delete_all
-
update_counter(-scope.delete_all)
-
else
-
update_counter(-scope.update_all(reflection.foreign_key => nil))
-
end
-
end
-
end
-
-
1
def foreign_key_present?
-
owner.attribute_present?(reflection.association_primary_key)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
module Associations
-
# Helper class module which gets mixed into JoinDependency::JoinAssociation and AssociationScope
-
1
module JoinHelper #:nodoc:
-
-
1
def join_type
-
Arel::InnerJoin
-
end
-
-
1
private
-
-
1
def construct_tables
-
12
tables = []
-
12
chain.each do |reflection|
-
tables << alias_tracker.aliased_table_for(
-
table_name_for(reflection),
-
table_alias_for(reflection, reflection != self.reflection)
-
12
)
-
-
12
if reflection.source_macro == :has_and_belongs_to_many
-
tables << alias_tracker.aliased_table_for(
-
(reflection.source_reflection || reflection).join_table,
-
table_alias_for(reflection, true)
-
)
-
end
-
end
-
12
tables
-
end
-
-
1
def table_name_for(reflection)
-
reflection.table_name
-
end
-
-
1
def table_alias_for(reflection, join = false)
-
12
name = "#{reflection.plural_name}_#{alias_suffix}"
-
12
name << "_join" if join
-
12
name
-
end
-
-
1
def join(table, constraint)
-
table.create_join(table, table.create_on(constraint), join_type)
-
end
-
end
-
end
-
end
-
1
module ActiveRecord
-
1
class PredicateBuilder # :nodoc:
-
1
def self.build_from_hash(klass, attributes, default_table)
-
66
queries = []
-
-
66
attributes.each do |column, value|
-
66
table = default_table
-
-
66
if value.is_a?(Hash)
-
62
if value.empty?
-
queries << '1=0'
-
else
-
62
table = Arel::Table.new(column, default_table.engine)
-
62
association = klass.reflect_on_association(column.to_sym)
-
-
62
value.each do |k, v|
-
62
queries.concat expand(association && association.klass, table, k, v)
-
end
-
end
-
else
-
4
column = column.to_s
-
-
4
if column.include?('.')
-
table_name, column = column.split('.', 2)
-
table = Arel::Table.new(table_name, default_table.engine)
-
end
-
-
4
queries.concat expand(klass, table, column, value)
-
end
-
end
-
-
66
queries
-
end
-
-
1
def self.expand(klass, table, column, value)
-
66
queries = []
-
-
# Find the foreign key when using queries such as:
-
# Post.where(author: author)
-
#
-
# For polymorphic relationships, find the foreign key and type:
-
# PriceEstimate.where(estimate_of: treasure)
-
66
if klass && value.class < Base && reflection = klass.reflect_on_association(column.to_sym)
-
if reflection.polymorphic?
-
queries << build(table[reflection.foreign_type], value.class.base_class)
-
end
-
-
column = reflection.foreign_key
-
end
-
-
66
queries << build(table[column], value)
-
66
queries
-
end
-
-
1
def self.references(attributes)
-
attributes.map do |key, value|
-
66
if value.is_a?(Hash)
-
62
key
-
else
-
4
key = key.to_s
-
4
key.split('.').first if key.include?('.')
-
end
-
66
end.compact
-
end
-
-
1
private
-
1
def self.build(attribute, value)
-
66
case value
-
when Array
-
values = value.to_a.map {|x| x.is_a?(Base) ? x.id : x}
-
ranges, values = values.partition {|v| v.is_a?(Range)}
-
-
values_predicate = if values.include?(nil)
-
values = values.compact
-
-
case values.length
-
when 0
-
attribute.eq(nil)
-
when 1
-
attribute.eq(values.first).or(attribute.eq(nil))
-
else
-
attribute.in(values).or(attribute.eq(nil))
-
end
-
else
-
attribute.in(values)
-
end
-
-
array_predicates = ranges.map { |range| attribute.in(range) }
-
array_predicates << values_predicate
-
array_predicates.inject { |composite, predicate| composite.or(predicate) }
-
when ActiveRecord::Relation
-
value = value.select(value.klass.arel_table[value.klass.primary_key]) if value.select_values.empty?
-
attribute.in(value.arel.ast)
-
when Range
-
attribute.in(value)
-
when ActiveRecord::Base
-
attribute.eq(value.id)
-
when Class
-
# FIXME: I think we need to deprecate this behavior
-
attribute.eq(value.name)
-
else
-
66
attribute.eq(value)
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
# Backtraces often include many lines that are not relevant for the context
-
# under review. This makes it hard to find the signal amongst the backtrace
-
# noise, and adds debugging time. With a BacktraceCleaner, filters and
-
# silencers are used to remove the noisy lines, so that only the most relevant
-
# lines remain.
-
#
-
# Filters are used to modify lines of data, while silencers are used to remove
-
# lines entirely. The typical filter use case is to remove lengthy path
-
# information from the start of each line, and view file paths relevant to the
-
# app directory instead of the file system root. The typical silencer use case
-
# is to exclude the output of a noisy library from the backtrace, so that you
-
# can focus on the rest.
-
#
-
# bc = BacktraceCleaner.new
-
# bc.add_filter { |line| line.gsub(Rails.root, '') }
-
# bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
-
# bc.clean(exception.backtrace) # will strip the Rails.root prefix and skip any lines from mongrel or rubygems
-
#
-
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
-
# and show as much data as possible, you can always call
-
# <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the
-
# backtrace to a pristine state. If you need to reconfigure an existing
-
# BacktraceCleaner so that it does not filter or modify the paths of any lines
-
# of the backtrace, you can call BacktraceCleaner#remove_filters! These two
-
# methods will give you a completely untouched backtrace.
-
#
-
# Inspired by the Quiet Backtrace gem by Thoughtbot.
-
1
class BacktraceCleaner
-
1
def initialize
-
1
@filters, @silencers = [], []
-
end
-
-
# Returns the backtrace after all filters and silencers have been run
-
# against it. Filters run first, then silencers.
-
1
def clean(backtrace, kind = :silent)
-
filtered = filter_backtrace(backtrace)
-
-
case kind
-
when :silent
-
silence(filtered)
-
when :noise
-
noise(filtered)
-
else
-
filtered
-
end
-
end
-
1
alias :filter :clean
-
-
# Adds a filter from the block provided. Each line in the backtrace will be
-
# mapped against this filter.
-
#
-
# # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
-
# backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
-
1
def add_filter(&block)
-
4
@filters << block
-
end
-
-
# Adds a silencer from the block provided. If the silencer returns +true+
-
# for a given line, it will be excluded from the clean backtrace.
-
#
-
# # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
-
# backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
-
1
def add_silencer(&block)
-
1
@silencers << block
-
end
-
-
# Will remove all silencers, but leave in the filters. This is useful if
-
# your context of debugging suddenly expands as you suspect a bug in one of
-
# the libraries you use.
-
1
def remove_silencers!
-
@silencers = []
-
end
-
-
# Removes all filters, but leaves in silencers. Useful if you suddenly
-
# need to see entire filepaths in the backtrace that you had already
-
# filtered out.
-
1
def remove_filters!
-
@filters = []
-
end
-
-
1
private
-
1
def filter_backtrace(backtrace)
-
@filters.each do |f|
-
backtrace = backtrace.map { |line| f.call(line) }
-
end
-
-
backtrace
-
end
-
-
1
def silence(backtrace)
-
@silencers.each do |s|
-
backtrace = backtrace.reject { |line| s.call(line) }
-
end
-
-
backtrace
-
end
-
-
1
def noise(backtrace)
-
backtrace - silence(backtrace)
-
end
-
end
-
end
-
# encoding: utf-8
-
1
require 'active_support/json'
-
1
require 'active_support/core_ext/string/access'
-
1
require 'active_support/core_ext/string/behavior'
-
1
require 'active_support/core_ext/module/delegation'
-
-
1
module ActiveSupport #:nodoc:
-
1
module Multibyte #:nodoc:
-
# Chars enables you to work transparently with UTF-8 encoding in the Ruby
-
# String class without having extensive knowledge about the encoding. A
-
# Chars object accepts a string upon initialization and proxies String
-
# methods in an encoding safe manner. All the normal String methods are also
-
# implemented on the proxy.
-
#
-
# String methods are proxied through the Chars object, and can be accessed
-
# through the +mb_chars+ method. Methods which would normally return a
-
# String object now return a Chars object so methods can be chained.
-
#
-
# 'The Perfect String '.mb_chars.downcase.strip.normalize # => "the perfect string"
-
#
-
# Chars objects are perfectly interchangeable with String objects as long as
-
# no explicit class checks are made. If certain methods do explicitly check
-
# the class, call +to_s+ before you pass chars objects to them.
-
#
-
# bad.explicit_checking_method 'T'.mb_chars.downcase.to_s
-
#
-
# The default Chars implementation assumes that the encoding of the string
-
# is UTF-8, if you want to handle different encodings you can write your own
-
# multibyte string handler and configure it through
-
# ActiveSupport::Multibyte.proxy_class.
-
#
-
# class CharsForUTF32
-
# def size
-
# @wrapped_string.size / 4
-
# end
-
#
-
# def self.accepts?(string)
-
# string.length % 4 == 0
-
# end
-
# end
-
#
-
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
-
1
class Chars
-
1
include Comparable
-
1
attr_reader :wrapped_string
-
1
alias to_s wrapped_string
-
1
alias to_str wrapped_string
-
-
1
delegate :<=>, :=~, :acts_like_string?, :to => :wrapped_string
-
-
# Creates a new Chars instance by wrapping _string_.
-
1
def initialize(string)
-
@wrapped_string = string
-
@wrapped_string.force_encoding(Encoding::UTF_8) unless @wrapped_string.frozen?
-
end
-
-
# Forward all undefined methods to the wrapped string.
-
1
def method_missing(method, *args, &block)
-
if method.to_s =~ /!$/
-
result = @wrapped_string.__send__(method, *args, &block)
-
self if result
-
else
-
result = @wrapped_string.__send__(method, *args, &block)
-
result.kind_of?(String) ? chars(result) : result
-
end
-
end
-
-
# Returns +true+ if _obj_ responds to the given method. Private methods
-
# are included in the search only if the optional second parameter
-
# evaluates to +true+.
-
1
def respond_to_missing?(method, include_private)
-
@wrapped_string.respond_to?(method, include_private)
-
end
-
-
# Returns +true+ when the proxy class can handle the string. Returns
-
# +false+ otherwise.
-
1
def self.consumes?(string)
-
string.encoding == Encoding::UTF_8
-
end
-
-
# Works just like <tt>String#split</tt>, with the exception that the items
-
# in the resulting list are Chars instances instead of String. This makes
-
# chaining methods easier.
-
#
-
# 'Café périferôl'.mb_chars.split(/é/).map { |part| part.upcase.to_s } # => ["CAF", " P", "RIFERÔL"]
-
1
def split(*args)
-
@wrapped_string.split(*args).map { |i| self.class.new(i) }
-
end
-
-
# Works like like <tt>String#slice!</tt>, but returns an instance of
-
# Chars, or nil if the string was not modified.
-
1
def slice!(*args)
-
chars(@wrapped_string.slice!(*args))
-
end
-
-
# Reverses all characters in the string.
-
#
-
# 'Café'.mb_chars.reverse.to_s # => 'éfaC'
-
1
def reverse
-
chars(Unicode.unpack_graphemes(@wrapped_string).reverse.flatten.pack('U*'))
-
end
-
-
# Limits the byte size of the string to a number of bytes without breaking
-
# characters. Usable when the storage for a string is limited for some
-
# reason.
-
#
-
# 'こんにちは'.mb_chars.limit(7).to_s # => "こん"
-
1
def limit(limit)
-
slice(0...translate_offset(limit))
-
end
-
-
# Converts characters in the string to uppercase.
-
#
-
# 'Laurent, où sont les tests ?'.mb_chars.upcase.to_s # => "LAURENT, OÙ SONT LES TESTS ?"
-
1
def upcase
-
chars Unicode.upcase(@wrapped_string)
-
end
-
-
# Converts characters in the string to lowercase.
-
#
-
# 'VĚDA A VÝZKUM'.mb_chars.downcase.to_s # => "věda a výzkum"
-
1
def downcase
-
chars Unicode.downcase(@wrapped_string)
-
end
-
-
# Converts characters in the string to the opposite case.
-
#
-
# 'El Cañón".mb_chars.swapcase.to_s # => "eL cAÑÓN"
-
1
def swapcase
-
chars Unicode.swapcase(@wrapped_string)
-
end
-
-
# Converts the first character to uppercase and the remainder to lowercase.
-
#
-
# 'über'.mb_chars.capitalize.to_s # => "Über"
-
1
def capitalize
-
(slice(0) || chars('')).upcase + (slice(1..-1) || chars('')).downcase
-
end
-
-
# Capitalizes the first letter of every word, when possible.
-
#
-
# "ÉL QUE SE ENTERÓ".mb_chars.titleize # => "Él Que Se Enteró"
-
# "日本語".mb_chars.titleize # => "日本語"
-
1
def titleize
-
chars(downcase.to_s.gsub(/\b('?\S)/u) { Unicode.upcase($1)})
-
end
-
1
alias_method :titlecase, :titleize
-
-
# Returns the KC normalization of the string by default. NFKC is
-
# considered the best normalization form for passing strings to databases
-
# and validations.
-
#
-
# * <tt>form</tt> - The form you want to normalize in. Should be one of the following:
-
# <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>. Default is
-
# ActiveSupport::Multibyte::Unicode.default_normalization_form
-
1
def normalize(form = nil)
-
chars(Unicode.normalize(@wrapped_string, form))
-
end
-
-
# Performs canonical decomposition on all the characters.
-
#
-
# 'é'.length # => 2
-
# 'é'.mb_chars.decompose.to_s.length # => 3
-
1
def decompose
-
chars(Unicode.decompose(:canonical, @wrapped_string.codepoints.to_a).pack('U*'))
-
end
-
-
# Performs composition on all the characters.
-
#
-
# 'é'.length # => 3
-
# 'é'.mb_chars.compose.to_s.length # => 2
-
1
def compose
-
chars(Unicode.compose(@wrapped_string.codepoints.to_a).pack('U*'))
-
end
-
-
# Returns the number of grapheme clusters in the string.
-
#
-
# 'क्षि'.mb_chars.length # => 4
-
# 'क्षि'.mb_chars.grapheme_length # => 3
-
1
def grapheme_length
-
Unicode.unpack_graphemes(@wrapped_string).length
-
end
-
-
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
-
# resulting in a valid UTF-8 string.
-
#
-
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
-
# encoding is entirely CP1252 or ISO-8859-1.
-
1
def tidy_bytes(force = false)
-
chars(Unicode.tidy_bytes(@wrapped_string, force))
-
end
-
-
1
def as_json(options = nil) #:nodoc:
-
to_s.as_json(options)
-
end
-
-
1
%w(capitalize downcase reverse tidy_bytes upcase).each do |method|
-
5
define_method("#{method}!") do |*args|
-
@wrapped_string = send(method, *args).to_s
-
self
-
end
-
end
-
-
1
protected
-
-
1
def translate_offset(byte_offset) #:nodoc:
-
return nil if byte_offset.nil?
-
return 0 if @wrapped_string == ''
-
-
begin
-
@wrapped_string.byteslice(0...byte_offset).unpack('U*').length
-
rescue ArgumentError
-
byte_offset -= 1
-
retry
-
end
-
end
-
-
1
def chars(string) #:nodoc:
-
self.class.new(string)
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
# This file loads up the parsers for mail to use. It also will attempt to compile parsers
-
# if they don't exist.
-
#
-
# It also only uses the compiler if we are running the SPEC suite
-
1
module Mail # :doc:
-
1
require 'treetop/runtime'
-
-
1
def self.compile_parser(parser)
-
require 'treetop/compiler'
-
Treetop.load(File.join(File.dirname(__FILE__)) + "/mail/parsers/#{parser}")
-
end
-
-
1
parsers = %w[ rfc2822_obsolete rfc2822 address_lists phrase_lists
-
date_time received message_ids envelope_from rfc2045
-
mime_version content_type content_disposition
-
content_transfer_encoding content_location ]
-
-
1
if defined?(MAIL_SPEC_SUITE_RUNNING)
-
parsers.each do |parser|
-
compile_parser(parser)
-
end
-
-
else
-
1
parsers.each do |parser|
-
14
begin
-
14
require "mail/parsers/#{parser}"
-
rescue LoadError
-
compile_parser(parser)
-
end
-
end
-
-
end
-
-
end
-
# encoding: utf-8
-
1
module Mail # :doc:
-
-
1
require 'date'
-
1
require 'shellwords'
-
-
1
require 'uri'
-
1
require 'net/smtp'
-
1
require 'mime/types'
-
-
1
if RUBY_VERSION <= '1.8.6'
-
begin
-
require 'tlsmail'
-
rescue LoadError
-
raise "You need to install tlsmail if you are using ruby <= 1.8.6"
-
end
-
end
-
-
1
if RUBY_VERSION >= "1.9.0"
-
1
require 'mail/version_specific/ruby_1_9'
-
1
RubyVer = Ruby19
-
else
-
require 'mail/version_specific/ruby_1_8'
-
RubyVer = Ruby18
-
end
-
-
1
require 'mail/version'
-
-
1
require 'mail/core_extensions/nil'
-
1
require 'mail/core_extensions/object'
-
1
require 'mail/core_extensions/string'
-
1
require 'mail/core_extensions/smtp' if RUBY_VERSION < '1.9.3'
-
1
require 'mail/indifferent_hash'
-
-
# Only load our multibyte extensions if AS is not already loaded
-
1
if defined?(ActiveSupport)
-
1
require 'active_support/inflector'
-
else
-
require 'mail/core_extensions/string/access'
-
require 'mail/core_extensions/string/multibyte'
-
require 'mail/multibyte'
-
end
-
-
1
require 'mail/patterns'
-
1
require 'mail/utilities'
-
1
require 'mail/configuration'
-
-
1
@@autoloads = {}
-
1
def self.register_autoload(name, path)
-
53
@@autoloads[name] = path
-
53
autoload(name, path)
-
end
-
-
# This runs through the autoload list and explictly requires them for you.
-
# Useful when running mail in a threaded process.
-
#
-
# Usage:
-
#
-
# require 'mail'
-
# Mail.eager_autoload!
-
1
def self.eager_autoload!
-
@@autoloads.each { |_,path| require(path) }
-
end
-
-
# Autoload mail send and receive classes.
-
1
require 'mail/network'
-
-
1
require 'mail/message'
-
1
require 'mail/part'
-
1
require 'mail/header'
-
1
require 'mail/parts_list'
-
1
require 'mail/attachments_list'
-
1
require 'mail/body'
-
1
require 'mail/field'
-
1
require 'mail/field_list'
-
-
1
require 'mail/envelope'
-
-
1
require 'load_parsers'
-
-
# Autoload header field elements and transfer encodings.
-
1
require 'mail/elements'
-
1
require 'mail/encodings'
-
1
require 'mail/encodings/base64'
-
1
require 'mail/encodings/quoted_printable'
-
-
1
require 'mail/matchers/has_sent_mail'
-
-
# Finally... require all the Mail.methods
-
1
require 'mail/mail'
-
end
-
1
module Mail
-
1
class AttachmentsList < Array
-
-
1
def initialize(parts_list)
-
4
@parts_list = parts_list
-
4
@content_disposition_type = 'attachment'
-
parts_list.map { |p|
-
if p.content_type == "message/rfc822"
-
Mail.new(p.body).attachments
-
elsif p.parts.empty?
-
p if p.attachment?
-
else
-
p.attachments
-
end
-
4
}.flatten.compact.each { |a| self << a }
-
4
self
-
end
-
-
1
def inline
-
@content_disposition_type = 'inline'
-
self
-
end
-
-
# Returns the attachment by filename or at index.
-
#
-
# mail.attachments['test.png'] = File.read('test.png')
-
# mail.attachments['test.jpg'] = File.read('test.jpg')
-
#
-
# mail.attachments['test.png'].filename #=> 'test.png'
-
# mail.attachments[1].filename #=> 'test.jpg'
-
1
def [](index_value)
-
if index_value.is_a?(Fixnum)
-
self.fetch(index_value)
-
else
-
self.select { |a| a.filename == index_value }.first
-
end
-
end
-
-
1
def []=(name, value)
-
encoded_name = Mail::Encodings.decode_encode name, :encode
-
default_values = { :content_type => "#{set_mime_type(name)}; filename=\"#{encoded_name}\"",
-
:content_transfer_encoding => "#{guess_encoding}",
-
:content_disposition => "#{@content_disposition_type}; filename=\"#{encoded_name}\"" }
-
-
if value.is_a?(Hash)
-
-
default_values[:body] = value.delete(:content) if value[:content]
-
-
default_values[:body] = value.delete(:data) if value[:data]
-
-
encoding = value.delete(:transfer_encoding) || value.delete(:encoding)
-
if encoding
-
if Mail::Encodings.defined? encoding
-
default_values[:content_transfer_encoding] = encoding
-
else
-
raise "Do not know how to handle Content Transfer Encoding #{encoding}, please choose either quoted-printable or base64"
-
end
-
end
-
-
if value[:mime_type]
-
default_values[:content_type] = value.delete(:mime_type)
-
@mime_type = MIME::Types[default_values[:content_type]].first
-
default_values[:content_transfer_encoding] ||= guess_encoding
-
end
-
-
hash = default_values.merge(value)
-
else
-
default_values[:body] = value
-
hash = default_values
-
end
-
-
if hash[:body].respond_to? :force_encoding and hash[:body].respond_to? :valid_encoding?
-
if not hash[:body].valid_encoding? and default_values[:content_transfer_encoding].downcase == "binary"
-
hash[:body].force_encoding("BINARY")
-
end
-
end
-
-
attachment = Part.new(hash)
-
attachment.add_content_id(hash[:content_id])
-
-
@parts_list << attachment
-
end
-
-
# Uses the mime type to try and guess the encoding, if it is a binary type, or unknown, then we
-
# set it to binary, otherwise as set to plain text
-
1
def guess_encoding
-
if @mime_type && !@mime_type.binary?
-
"7bit"
-
else
-
"binary"
-
end
-
end
-
-
1
def set_mime_type(filename)
-
# Have to do this because MIME::Types is not Ruby 1.9 safe yet
-
if RUBY_VERSION >= '1.9'
-
filename = filename.encode(Encoding::UTF_8) if filename.respond_to?(:encode)
-
end
-
-
@mime_type = MIME::Types.type_for(filename).first
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
-
# = Body
-
#
-
# The body is where the text of the email is stored. Mail treats the body
-
# as a single object. The body itself has no information about boundaries
-
# used in the MIME standard, it just looks at its content as either a single
-
# block of text, or (if it is a multipart message) as an array of blocks of text.
-
#
-
# A body has to be told to split itself up into a multipart message by calling
-
# #split with the correct boundary. This is because the body object has no way
-
# of knowing what the correct boundary is for itself (there could be many
-
# boundaries in a body in the case of a nested MIME text).
-
#
-
# Once split is called, Mail::Body will slice itself up on this boundary,
-
# assigning anything that appears before the first part to the preamble, and
-
# anything that appears after the closing boundary to the epilogue, then
-
# each part gets initialized into a Mail::Part object.
-
#
-
# The boundary that is used to split up the Body is also stored in the Body
-
# object for use on encoding itself back out to a string. You can
-
# overwrite this if it needs to be changed.
-
#
-
# On encoding, the body will return the preamble, then each part joined by
-
# the boundary, followed by a closing boundary string and then the epilogue.
-
1
class Body
-
-
1
def initialize(string = '')
-
6
@boundary = nil
-
6
@preamble = nil
-
6
@epilogue = nil
-
6
@charset = nil
-
6
@part_sort_order = [ "text/plain", "text/enriched", "text/html" ]
-
6
@parts = Mail::PartsList.new
-
6
if string.blank?
-
4
@raw_source = ''
-
else
-
# Do join first incase we have been given an Array in Ruby 1.9
-
2
if string.respond_to?(:join)
-
@raw_source = string.join('')
-
elsif string.respond_to?(:to_s)
-
2
@raw_source = string.to_s
-
else
-
raise "You can only assign a string or an object that responds_to? :join or :to_s to a body."
-
end
-
end
-
6
@encoding = (only_us_ascii? ? '7bit' : '8bit')
-
6
set_charset
-
end
-
-
# Matches this body with another body. Also matches the decoded value of this
-
# body with a string.
-
#
-
# Examples:
-
#
-
# body = Mail::Body.new('The body')
-
# body == body #=> true
-
#
-
# body = Mail::Body.new('The body')
-
# body == 'The body' #=> true
-
#
-
# body = Mail::Body.new("VGhlIGJvZHk=\n")
-
# body.encoding = 'base64'
-
# body == "The body" #=> true
-
1
def ==(other)
-
if other.class == String
-
self.decoded == other
-
else
-
super
-
end
-
end
-
-
# Accepts a string and performs a regular expression against the decoded text
-
#
-
# Examples:
-
#
-
# body = Mail::Body.new('The body')
-
# body =~ /The/ #=> 0
-
#
-
# body = Mail::Body.new("VGhlIGJvZHk=\n")
-
# body.encoding = 'base64'
-
# body =~ /The/ #=> 0
-
1
def =~(regexp)
-
self.decoded =~ regexp
-
end
-
-
# Accepts a string and performs a regular expression against the decoded text
-
#
-
# Examples:
-
#
-
# body = Mail::Body.new('The body')
-
# body.match(/The/) #=> #<MatchData "The">
-
#
-
# body = Mail::Body.new("VGhlIGJvZHk=\n")
-
# body.encoding = 'base64'
-
# body.match(/The/) #=> #<MatchData "The">
-
1
def match(regexp)
-
self.decoded.match(regexp)
-
end
-
-
# Accepts anything that responds to #to_s and checks if it's a substring of the decoded text
-
#
-
# Examples:
-
#
-
# body = Mail::Body.new('The body')
-
# body.include?('The') #=> true
-
#
-
# body = Mail::Body.new("VGhlIGJvZHk=\n")
-
# body.encoding = 'base64'
-
# body.include?('The') #=> true
-
1
def include?(other)
-
self.decoded.include?(other.to_s)
-
end
-
-
# Allows you to set the sort order of the parts, overriding the default sort order.
-
# Defaults to 'text/plain', then 'text/enriched', then 'text/html' with any other content
-
# type coming after.
-
1
def set_sort_order(order)
-
@part_sort_order = order
-
end
-
-
# Allows you to sort the parts according to the default sort order, or the sort order you
-
# set with :set_sort_order.
-
#
-
# sort_parts! is also called from :encode, so there is no need for you to call this explicitly
-
1
def sort_parts!
-
@parts.each do |p|
-
p.body.set_sort_order(@part_sort_order)
-
@parts.sort!(@part_sort_order)
-
p.body.sort_parts!
-
end
-
end
-
-
# Returns the raw source that the body was initialized with, without
-
# any tampering
-
1
def raw_source
-
14
@raw_source
-
end
-
-
1
def get_best_encoding(target)
-
1
target_encoding = Mail::Encodings.get_encoding(target)
-
1
target_encoding.get_best_compatible(encoding, raw_source)
-
end
-
-
# Returns a body encoded using transfer_encoding. Multipart always uses an
-
# identiy encoding (i.e. no encoding).
-
# Calling this directly is not a good idea, but supported for compatibility
-
# TODO: Validate that preamble and epilogue are valid for requested encoding
-
1
def encoded(transfer_encoding = '8bit')
-
1
if multipart?
-
self.sort_parts!
-
encoded_parts = parts.map { |p| p.encoded }
-
([preamble] + encoded_parts).join(crlf_boundary) + end_boundary + epilogue.to_s
-
else
-
1
be = get_best_encoding(transfer_encoding)
-
1
dec = Mail::Encodings::get_encoding(encoding)
-
1
enc = Mail::Encodings::get_encoding(be)
-
1
if transfer_encoding == encoding and dec.nil?
-
# Cannot decode, so skip normalization
-
raw_source
-
else
-
# Decode then encode to normalize and allow transforming
-
# from base64 to Q-P and vice versa
-
1
decoded = dec.decode(raw_source)
-
1
if defined?(Encoding) && charset && charset != "US-ASCII"
-
decoded.encode!(charset)
-
decoded.force_encoding('BINARY') unless Encoding.find(charset).ascii_compatible?
-
end
-
1
enc.encode(decoded)
-
end
-
end
-
end
-
-
1
def decoded
-
if !Encodings.defined?(encoding)
-
raise UnknownEncodingType, "Don't know how to decode #{encoding}, please call #encoded and decode it yourself."
-
else
-
Encodings.get_encoding(encoding).decode(raw_source)
-
end
-
end
-
-
1
def to_s
-
decoded
-
end
-
-
1
def charset
-
2
@charset
-
end
-
-
1
def charset=( val )
-
@charset = val
-
end
-
-
1
def encoding(val = nil)
-
3
if val
-
self.encoding = val
-
else
-
3
@encoding
-
end
-
end
-
-
1
def encoding=( val )
-
@encoding = if val == "text" || val.blank?
-
(only_us_ascii? ? '7bit' : '8bit')
-
else
-
val
-
end
-
end
-
-
# Returns the preamble (any text that is before the first MIME boundary)
-
1
def preamble
-
@preamble
-
end
-
-
# Sets the preamble to a string (adds text before the first MIME boundary)
-
1
def preamble=( val )
-
@preamble = val
-
end
-
-
# Returns the epilogue (any text that is after the last MIME boundary)
-
1
def epilogue
-
@epilogue
-
end
-
-
# Sets the epilogue to a string (adds text after the last MIME boundary)
-
1
def epilogue=( val )
-
@epilogue = val
-
end
-
-
# Returns true if there are parts defined in the body
-
1
def multipart?
-
3
true unless parts.empty?
-
end
-
-
# Returns the boundary used by the body
-
1
def boundary
-
@boundary
-
end
-
-
# Allows you to change the boundary of this Body object
-
1
def boundary=( val )
-
@boundary = val
-
end
-
-
1
def parts
-
7
@parts
-
end
-
-
1
def <<( val )
-
if @parts
-
@parts << val
-
else
-
@parts = Mail::PartsList.new[val]
-
end
-
end
-
-
1
def split!(boundary)
-
self.boundary = boundary
-
parts = raw_source.split(/(?:\A|\r\n)--#{Regexp.escape(boundary)}(?=(?:--)?\s*$)/)
-
# Make the preamble equal to the preamble (if any)
-
self.preamble = parts[0].to_s.strip
-
# Make the epilogue equal to the epilogue (if any)
-
self.epilogue = parts[-1].to_s.sub('--', '').strip
-
parts[1...-1].to_a.each { |part| @parts << Mail::Part.new(part) }
-
self
-
end
-
-
1
def only_us_ascii?
-
12
!(raw_source =~ /[^\x01-\x7f]/)
-
end
-
-
1
def empty?
-
!!raw_source.to_s.empty?
-
end
-
-
1
private
-
-
1
def crlf_boundary
-
"\r\n--#{boundary}\r\n"
-
end
-
-
1
def end_boundary
-
"\r\n--#{boundary}--\r\n"
-
end
-
-
1
def set_charset
-
6
only_us_ascii? ? @charset = 'US-ASCII' : @charset = nil
-
end
-
end
-
end
-
1
module Mail
-
1
module CheckDeliveryParams
-
1
def check_delivery_params(mail)
-
if mail.smtp_envelope_from.blank?
-
raise ArgumentError.new('An SMTP From address is required to send a message. Set the message smtp_envelope_from, return_path, sender, or from address.')
-
end
-
-
if mail.smtp_envelope_to.blank?
-
raise ArgumentError.new('An SMTP To address is required to send a message. Set the message smtp_envelope_to, to, cc, or bcc address.')
-
end
-
-
message = mail.encoded if mail.respond_to?(:encoded)
-
if message.blank?
-
raise ArgumentError.new('An encoded message is required to send an email')
-
end
-
-
[mail.smtp_envelope_from, mail.smtp_envelope_to, message]
-
end
-
end
-
end
-
# encoding: utf-8
-
#
-
# Thanks to Nicolas Fouché for this wrapper
-
#
-
1
require 'singleton'
-
-
1
module Mail
-
-
# The Configuration class is a Singleton used to hold the default
-
# configuration for all Mail objects.
-
#
-
# Each new mail object gets a copy of these values at initialization
-
# which can be overwritten on a per mail object basis.
-
1
class Configuration
-
1
include Singleton
-
-
1
def initialize
-
1
@delivery_method = nil
-
1
@retriever_method = nil
-
1
super
-
end
-
-
1
def delivery_method(method = nil, settings = {})
-
4
return @delivery_method if @delivery_method && method.nil?
-
1
@delivery_method = lookup_delivery_method(method).new(settings)
-
end
-
-
1
def lookup_delivery_method(method)
-
3
case method.is_a?(String) ? method.to_sym : method
-
when nil
-
1
Mail::SMTP
-
when :smtp
-
Mail::SMTP
-
when :sendmail
-
Mail::Sendmail
-
when :exim
-
Mail::Exim
-
when :file
-
Mail::FileDelivery
-
when :smtp_connection
-
Mail::SMTPConnection
-
when :test
-
Mail::TestMailer
-
else
-
2
method
-
end
-
end
-
-
1
def retriever_method(method = nil, settings = {})
-
return @retriever_method if @retriever_method && method.nil?
-
@retriever_method = lookup_retriever_method(method).new(settings)
-
end
-
-
1
def lookup_retriever_method(method)
-
case method
-
when nil
-
Mail::POP3
-
when :pop3
-
Mail::POP3
-
when :imap
-
Mail::IMAP
-
when :test
-
Mail::TestRetriever
-
else
-
method
-
end
-
end
-
-
1
def param_encode_language(value = nil)
-
value ? @encode_language = value : @encode_language ||= 'en'
-
end
-
-
end
-
-
end
-
# encoding: utf-8
-
-
# This is not loaded if ActiveSupport is already loaded
-
-
1
class NilClass #:nodoc:
-
1
unless nil.respond_to? :blank?
-
def blank?
-
true
-
end
-
end
-
-
1
def to_crlf
-
4
''
-
end
-
-
1
def to_lf
-
''
-
end
-
end
-
# encoding: utf-8
-
-
1
unless Object.method_defined? :blank?
-
class Object
-
def blank?
-
if respond_to?(:empty?)
-
empty?
-
else
-
!self
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
1
class String #:nodoc:
-
1
def to_crlf
-
7
to_str.gsub(/\n|\r\n|\r/) { "\r\n" }
-
end
-
-
1
def to_lf
-
3
to_str.gsub(/\n|\r\n|\r/) { "\n" }
-
end
-
-
185
unless String.instance_methods(false).map {|m| m.to_sym}.include?(:blank?)
-
def blank?
-
self !~ /\S/
-
end
-
end
-
-
1
unless method_defined?(:ascii_only?)
-
# Backport from Ruby 1.9 checks for non-us-ascii characters.
-
def ascii_only?
-
self !~ MATCH_NON_US_ASCII
-
end
-
-
MATCH_NON_US_ASCII = /[^\x00-\x7f]/
-
end
-
-
1
def not_ascii_only?
-
!ascii_only?
-
end
-
-
1
unless method_defined?(:bytesize)
-
alias :bytesize :length
-
end
-
end
-
1
module Mail
-
1
register_autoload :Address, 'mail/elements/address'
-
1
register_autoload :AddressList, 'mail/elements/address_list'
-
1
register_autoload :ContentDispositionElement, 'mail/elements/content_disposition_element'
-
1
register_autoload :ContentLocationElement, 'mail/elements/content_location_element'
-
1
register_autoload :ContentTransferEncodingElement, 'mail/elements/content_transfer_encoding_element'
-
1
register_autoload :ContentTypeElement, 'mail/elements/content_type_element'
-
1
register_autoload :DateTimeElement, 'mail/elements/date_time_element'
-
1
register_autoload :EnvelopeFromElement, 'mail/elements/envelope_from_element'
-
1
register_autoload :MessageIdsElement, 'mail/elements/message_ids_element'
-
1
register_autoload :MimeVersionElement, 'mail/elements/mime_version_element'
-
1
register_autoload :PhraseList, 'mail/elements/phrase_list'
-
1
register_autoload :ReceivedElement, 'mail/elements/received_element'
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
class Address
-
-
1
include Mail::Utilities
-
-
# Mail::Address handles all email addresses in Mail. It takes an email address string
-
# and parses it, breaking it down into its component parts and allowing you to get the
-
# address, comments, display name, name, local part, domain part and fully formatted
-
# address.
-
#
-
# Mail::Address requires a correctly formatted email address per RFC2822 or RFC822. It
-
# handles all obsolete versions including obsolete domain routing on the local part.
-
#
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
-
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
-
# a.address #=> 'mikel@test.lindsaar.net'
-
# a.display_name #=> 'Mikel Lindsaar'
-
# a.local #=> 'mikel'
-
# a.domain #=> 'test.lindsaar.net'
-
# a.comments #=> ['My email address']
-
# a.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
-
1
def initialize(value = nil)
-
2
@output_type = :decode
-
2
@tree = nil
-
2
@raw_text = value
-
case
-
when value.nil?
-
@parsed = false
-
return
-
else
-
2
parse(value)
-
2
end
-
end
-
-
# Returns the raw imput of the passed in string, this is before it is passed
-
# by the parser.
-
1
def raw
-
@raw_text
-
end
-
-
# Returns a correctly formatted address for the email going out. If given
-
# an incorrectly formatted address as input, Mail::Address will do its best
-
# to format it correctly. This includes quoting display names as needed and
-
# putting the address in angle brackets etc.
-
#
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
-
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
-
1
def format
-
parse unless @parsed
-
case
-
when tree.nil?
-
''
-
when display_name
-
[quote_phrase(display_name), "<#{address}>", format_comments].compact.join(" ")
-
when address
-
[address, format_comments].compact.join(" ")
-
else
-
tree.text_value
-
end
-
end
-
-
# Returns the address that is in the address itself. That is, the
-
# local@domain string, without any angle brackets or the like.
-
#
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
-
# a.address #=> 'mikel@test.lindsaar.net'
-
1
def address
-
2
parse unless @parsed
-
2
domain ? "#{local}@#{domain}" : local
-
end
-
-
# Provides a way to assign an address to an already made Mail::Address object.
-
#
-
# a = Address.new
-
# a.address = 'Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>'
-
# a.address #=> 'mikel@test.lindsaar.net'
-
1
def address=(value)
-
parse(value)
-
end
-
-
# Returns the display name of the email address passed in.
-
#
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
-
# a.display_name #=> 'Mikel Lindsaar'
-
1
def display_name
-
parse unless @parsed
-
@display_name ||= get_display_name
-
Encodings.decode_encode(@display_name.to_s, @output_type) if @display_name
-
end
-
-
# Provides a way to assign a display name to an already made Mail::Address object.
-
#
-
# a = Address.new
-
# a.address = 'mikel@test.lindsaar.net'
-
# a.display_name = 'Mikel Lindsaar'
-
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>'
-
1
def display_name=( str )
-
@display_name = str
-
end
-
-
# Returns the local part (the left hand side of the @ sign in the email address) of
-
# the address
-
#
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
-
# a.local #=> 'mikel'
-
1
def local
-
2
parse unless @parsed
-
2
"#{obs_domain_list}#{get_local.strip}" if get_local
-
end
-
-
# Returns the domain part (the right hand side of the @ sign in the email address) of
-
# the address
-
#
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
-
# a.domain #=> 'test.lindsaar.net'
-
1
def domain
-
4
parse unless @parsed
-
4
strip_all_comments(get_domain) if get_domain
-
end
-
-
# Returns an array of comments that are in the email, or an empty array if there
-
# are no comments
-
#
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
-
# a.comments #=> ['My email address']
-
1
def comments
-
4
parse unless @parsed
-
4
if get_comments.empty?
-
nil
-
else
-
get_comments.map { |c| c.squeeze(" ") }
-
end
-
end
-
-
# Sometimes an address will not have a display name, but might have the name
-
# as a comment field after the address. This returns that name if it exists.
-
#
-
# a = Address.new('mikel@test.lindsaar.net (Mikel Lindsaar)')
-
# a.name #=> 'Mikel Lindsaar'
-
1
def name
-
parse unless @parsed
-
get_name
-
end
-
-
# Returns the format of the address, or returns nothing
-
#
-
# a = Address.new('Mikel Lindsaar (My email address) <mikel@test.lindsaar.net>')
-
# a.format #=> 'Mikel Lindsaar <mikel@test.lindsaar.net> (My email address)'
-
1
def to_s
-
parse unless @parsed
-
format
-
end
-
-
# Shows the Address object basic details, including the Address
-
# a = Address.new('Mikel (My email) <mikel@test.lindsaar.net>')
-
# a.inspect #=> "#<Mail::Address:14184910 Address: |Mikel <mikel@test.lindsaar.net> (My email)| >"
-
1
def inspect
-
parse unless @parsed
-
"#<#{self.class}:#{self.object_id} Address: |#{to_s}| >"
-
end
-
-
1
def encoded
-
@output_type = :encode
-
format
-
end
-
-
1
def decoded
-
@output_type = :decode
-
format
-
end
-
-
1
private
-
-
1
def parse(value = nil)
-
2
@parsed = true
-
case
-
when value.nil?
-
nil
-
when value.class == String
-
self.tree = Mail::AddressList.new(value).address_nodes.first
-
else
-
2
self.tree = value
-
2
end
-
end
-
-
-
1
def get_domain
-
8
if tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:domain)
-
@domain_text ||= tree.angle_addr.addr_spec.domain.text_value.strip
-
8
elsif tree.respond_to?(:domain)
-
8
@domain_text ||= tree.domain.text_value.strip
-
elsif tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:domain)
-
tree.addr_spec.domain.text_value.strip
-
else
-
nil
-
end
-
end
-
-
1
def strip_all_comments(string)
-
4
unless comments.blank?
-
comments.each do |comment|
-
string = string.gsub("(#{comment})", '')
-
end
-
end
-
4
string.strip
-
end
-
-
1
def strip_domain_comments(value)
-
unless comments.blank?
-
comments.each do |comment|
-
if get_domain && get_domain.include?("(#{comment})")
-
value = value.gsub("(#{comment})", '')
-
end
-
end
-
end
-
value.to_s.strip
-
end
-
-
1
def get_comments
-
4
if tree.respond_to?(:comments)
-
4
@comments = tree.comments.map { |c| unparen(c.text_value.to_str) }
-
else
-
@comments = []
-
end
-
end
-
-
1
def get_display_name
-
if tree.respond_to?(:display_name)
-
name = unquote(tree.display_name.text_value.strip)
-
str = strip_all_comments(name.to_s)
-
elsif comments
-
if domain
-
str = strip_domain_comments(format_comments)
-
else
-
str = nil
-
end
-
else
-
nil
-
end
-
-
if str.blank?
-
nil
-
else
-
str
-
end
-
end
-
-
1
def get_name
-
if display_name
-
str = display_name
-
else
-
if comments
-
comment_text = comments.join(' ').squeeze(" ")
-
str = "(#{comment_text})"
-
end
-
end
-
-
if str.blank?
-
nil
-
else
-
unparen(str)
-
end
-
end
-
-
# Provides access to the Treetop parse tree for this address
-
1
def tree
-
60
@tree
-
end
-
-
1
def tree=(value)
-
2
@tree = value
-
end
-
-
1
def format_comments
-
if comments
-
comment_text = comments.map {|c| escape_paren(c) }.join(' ').squeeze(" ")
-
@format_comments ||= "(#{comment_text})"
-
else
-
nil
-
end
-
end
-
-
1
def obs_domain_list
-
2
if tree.respond_to?(:angle_addr)
-
obs = tree.angle_addr.elements.select { |e| e.respond_to?(:obs_domain_list) }
-
!obs.empty? ? obs.first.text_value : nil
-
else
-
nil
-
end
-
end
-
-
1
def get_local
-
case
-
when tree.respond_to?(:local_dot_atom_text)
-
tree.local_dot_atom_text.text_value
-
when tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:local_part)
-
tree.angle_addr.addr_spec.local_part.text_value
-
when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_part)
-
tree.addr_spec.local_part.text_value
-
when tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:local_dot_atom_text)
-
# Ignore local dot atom text when in angle brackets
-
nil
-
when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_dot_atom_text)
-
# Ignore local dot atom text when in angle brackets
-
nil
-
else
-
4
tree && tree.respond_to?(:local_part) ? tree.local_part.text_value : nil
-
4
end
-
end
-
-
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
class AddressList # :nodoc:
-
-
# Mail::AddressList is the class that parses To, From and other address fields from
-
# emails passed into Mail.
-
#
-
# AddressList provides a way to query the groups and mailbox lists of the passed in
-
# string.
-
#
-
# It can supply all addresses in an array, or return each address as an address object.
-
#
-
# Mail::AddressList requires a correctly formatted group or mailbox list per RFC2822 or
-
# RFC822. It also handles all obsolete versions in those RFCs.
-
#
-
# list = 'ada@test.lindsaar.net, My Group: mikel@test.lindsaar.net, Bob <bob@test.lindsaar.net>;'
-
# a = AddressList.new(list)
-
# a.addresses #=> [#<Mail::Address:14943130 Address: |ada@test.lindsaar.net...
-
# a.group_names #=> ["My Group"]
-
1
def initialize(string)
-
8
if string.blank?
-
@address_nodes = []
-
return self
-
end
-
8
parser = Mail::AddressListsParser.new
-
8
if tree = parser.parse(string)
-
8
@address_nodes = tree.addresses
-
else
-
raise Mail::Field::ParseError.new(AddressListsParser, string, parser.failure_reason)
-
end
-
end
-
-
# Returns a list of address objects from the parsed line
-
1
def addresses
-
@addresses ||= get_addresses.map do |address_tree|
-
2
Mail::Address.new(address_tree)
-
2
end
-
end
-
-
# Returns a list of all recipient syntax trees that are not part of a group
-
1
def individual_recipients # :nodoc:
-
2
@individual_recipients ||= @address_nodes - group_recipients
-
end
-
-
# Returns a list of all recipient syntax trees that are part of a group
-
1
def group_recipients # :nodoc:
-
6
@group_recipients ||= @address_nodes.select { |an| an.respond_to?(:group_name) }
-
end
-
-
# Returns the names as an array of strings of all groups
-
1
def group_names # :nodoc:
-
group_recipients.map { |g| g.group_name.text_value }
-
end
-
-
# Returns a list of address syntax trees
-
1
def address_nodes # :nodoc:
-
@address_nodes
-
end
-
-
1
private
-
-
1
def get_addresses
-
2
(individual_recipients + group_recipients.map { |g| get_group_addresses(g) }).flatten
-
end
-
-
1
def get_group_addresses(g)
-
if g.group_list.respond_to?(:addresses)
-
g.group_list.addresses
-
else
-
[]
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
class ContentTypeElement # :nodoc:
-
-
1
include Mail::Utilities
-
-
1
def initialize( string )
-
6
parser = Mail::ContentTypeParser.new
-
6
if tree = parser.parse(cleaned(string))
-
6
@main_type = tree.main_type.text_value.downcase
-
6
@sub_type = tree.sub_type.text_value.downcase
-
6
@parameters = tree.parameters
-
else
-
raise Mail::Field::ParseError.new(ContentTypeElement, string, parser.failure_reason)
-
end
-
end
-
-
1
def main_type
-
4
@main_type
-
end
-
-
1
def sub_type
-
2
@sub_type
-
end
-
-
1
def parameters
-
4
@parameters
-
end
-
-
1
def cleaned(string)
-
6
string =~ /(.+);\s*$/ ? $1 : string
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
class MimeVersionElement
-
-
1
include Mail::Utilities
-
-
1
def initialize( string )
-
4
parser = Mail::MimeVersionParser.new
-
4
if tree = parser.parse(string)
-
4
@major = tree.major.text_value
-
4
@minor = tree.minor.text_value
-
else
-
raise Mail::Field::ParseError.new(MimeVersionElement, string, parser.failure_reason)
-
end
-
end
-
-
1
def major
-
@major
-
end
-
-
1
def minor
-
@minor
-
end
-
-
end
-
end
-
# encoding: utf-8
-
-
1
module Mail
-
# Raised when attempting to decode an unknown encoding type
-
1
class UnknownEncodingType < StandardError #:nodoc:
-
end
-
-
1
module Encodings
-
-
1
include Mail::Patterns
-
1
extend Mail::Utilities
-
-
1
@transfer_encodings = {}
-
-
# Register transfer encoding
-
#
-
# Example
-
#
-
# Encodings.register "base64", Mail::Encodings::Base64
-
1
def Encodings.register(name, cls)
-
5
@transfer_encodings[get_name(name)] = cls
-
end
-
-
# Is the encoding we want defined?
-
#
-
# Example:
-
#
-
# Encodings.defined?(:base64) #=> true
-
1
def Encodings.defined?( str )
-
1
@transfer_encodings.include? get_name(str)
-
end
-
-
# Gets a defined encoding type, QuotedPrintable or Base64 for now.
-
#
-
# Each encoding needs to be defined as a Mail::Encodings::ClassName for
-
# this to work, allows us to add other encodings in the future.
-
#
-
# Example:
-
#
-
# Encodings.get_encoding(:base64) #=> Mail::Encodings::Base64
-
1
def Encodings.get_encoding( str )
-
8
@transfer_encodings[get_name(str)]
-
end
-
-
1
def Encodings.get_all
-
@transfer_encodings.values
-
end
-
-
1
def Encodings.get_name(enc)
-
15
enc = enc.to_s.gsub("-", "_").downcase
-
end
-
-
# Encodes a parameter value using URI Escaping, note the language field 'en' can
-
# be set using Mail::Configuration, like so:
-
#
-
# Mail.defaults do
-
# param_encode_language 'jp'
-
# end
-
#
-
# The character set used for encoding will either be the value of $KCODE for
-
# Ruby < 1.9 or the encoding on the string passed in.
-
#
-
# Example:
-
#
-
# Mail::Encodings.param_encode("This is fun") #=> "us-ascii'en'This%20is%20fun"
-
1
def Encodings.param_encode(str)
-
case
-
when str.ascii_only? && str =~ TOKEN_UNSAFE
-
%Q{"#{str}"}
-
when str.ascii_only?
-
2
str
-
else
-
RubyVer.param_encode(str)
-
2
end
-
end
-
-
# Decodes a parameter value using URI Escaping.
-
#
-
# Example:
-
#
-
# Mail::Encodings.param_decode("This%20is%20fun", 'us-ascii') #=> "This is fun"
-
#
-
# str = Mail::Encodings.param_decode("This%20is%20fun", 'iso-8559-1')
-
# str.encoding #=> 'ISO-8859-1' ## Only on Ruby 1.9
-
# str #=> "This is fun"
-
1
def Encodings.param_decode(str, encoding)
-
RubyVer.param_decode(str, encoding)
-
end
-
-
# Decodes or encodes a string as needed for either Base64 or QP encoding types in
-
# the =?<encoding>?[QB]?<string>?=" format.
-
#
-
# The output type needs to be :decode to decode the input string or :encode to
-
# encode the input string. The character set used for encoding will either be
-
# the value of $KCODE for Ruby < 1.9 or the encoding on the string passed in.
-
#
-
# On encoding, will only send out Base64 encoded strings.
-
1
def Encodings.decode_encode(str, output_type)
-
case
-
when output_type == :decode
-
1
Encodings.value_decode(str)
-
else
-
if str.ascii_only?
-
str
-
else
-
Encodings.b_value_encode(str, find_encoding(str))
-
end
-
1
end
-
end
-
-
# Decodes a given string as Base64 or Quoted Printable, depending on what
-
# type it is.
-
#
-
# String has to be of the format =?<encoding>?[QB]?<string>?=
-
1
def Encodings.value_decode(str)
-
# Optimization: If there's no encoded-words in the string, just return it
-
1
return str unless str =~ /\=\?[^?]+\?[QB]\?[^?]+?\?\=/xmi
-
-
lines = collapse_adjacent_encodings(str)
-
-
# Split on white-space boundaries with capture, so we capture the white-space as well
-
lines.map do |line|
-
line.split(/([ \t])/).map do |text|
-
if text.index('=?').nil?
-
text
-
else
-
# Search for occurences of quoted strings or plain strings
-
text.scan(/( # Group around entire regex to include it in matches
-
\=\?[^?]+\?([QB])\?[^?]+?\?\= # Quoted String with subgroup for encoding method
-
| # or
-
.+?(?=\=\?|$) # Plain String
-
)/xmi).map do |matches|
-
string, method = *matches
-
if method == 'b' || method == 'B'
-
b_value_decode(string)
-
elsif method == 'q' || method == 'Q'
-
q_value_decode(string)
-
else
-
string
-
end
-
end
-
end
-
end
-
end.flatten.join("")
-
end
-
-
# Takes an encoded string of the format =?<encoding>?[QB]?<string>?=
-
1
def Encodings.unquote_and_convert_to(str, to_encoding)
-
output = value_decode( str ).to_s # output is already converted to UTF-8
-
-
if 'utf8' == to_encoding.to_s.downcase.gsub("-", "")
-
output
-
elsif to_encoding
-
begin
-
if RUBY_VERSION >= '1.9'
-
output.encode(to_encoding)
-
else
-
require 'iconv'
-
Iconv.iconv(to_encoding, 'UTF-8', output).first
-
end
-
rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
-
# the 'from' parameter specifies a charset other than what the text
-
# actually is...not much we can do in this case but just return the
-
# unconverted text.
-
#
-
# Ditto if either parameter represents an unknown charset, like
-
# X-UNKNOWN.
-
output
-
end
-
else
-
output
-
end
-
end
-
-
1
def Encodings.address_encode(address, charset = 'utf-8')
-
8
if address.is_a?(Array)
-
# loop back through for each element
-
address.compact.map { |a| Encodings.address_encode(a, charset) }.join(", ")
-
else
-
# find any word boundary that is not ascii and encode it
-
8
encode_non_usascii(address, charset) if address
-
end
-
end
-
-
1
def Encodings.encode_non_usascii(address, charset)
-
8
return address if address.ascii_only? or charset.nil?
-
us_ascii = %Q{\x00-\x7f}
-
# Encode any non usascii strings embedded inside of quotes
-
address = address.gsub(/(".*?[^#{us_ascii}].*?")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
-
# Then loop through all remaining items and encode as needed
-
tokens = address.split(/\s/)
-
map_with_index(tokens) do |word, i|
-
if word.ascii_only?
-
word
-
else
-
previous_non_ascii = i>0 && tokens[i-1] && !tokens[i-1].ascii_only?
-
if previous_non_ascii #why are we adding an extra space here?
-
word = " #{word}"
-
end
-
Encodings.b_value_encode(word, charset)
-
end
-
end.join(' ')
-
end
-
-
# Encode a string with Base64 Encoding and returns it ready to be inserted
-
# as a value for a field, that is, in the =?<charset>?B?<string>?= format
-
#
-
# Example:
-
#
-
# Encodings.b_value_encode('This is あ string', 'UTF-8')
-
# #=> "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?="
-
1
def Encodings.b_value_encode(encoded_str, encoding = nil)
-
return encoded_str if encoded_str.to_s.ascii_only?
-
string, encoding = RubyVer.b_value_encode(encoded_str, encoding)
-
map_lines(string) do |str|
-
"=?#{encoding}?B?#{str.chomp}?="
-
end.join(" ")
-
end
-
-
# Encode a string with Quoted-Printable Encoding and returns it ready to be inserted
-
# as a value for a field, that is, in the =?<charset>?Q?<string>?= format
-
#
-
# Example:
-
#
-
# Encodings.q_value_encode('This is あ string', 'UTF-8')
-
# #=> "=?UTF-8?Q?This_is_=E3=81=82_string?="
-
1
def Encodings.q_value_encode(encoded_str, encoding = nil)
-
return encoded_str if encoded_str.to_s.ascii_only?
-
string, encoding = RubyVer.q_value_encode(encoded_str, encoding)
-
string.gsub!("=\r\n", '') # We already have limited the string to the length we want
-
map_lines(string) do |str|
-
"=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
-
end.join(" ")
-
end
-
-
1
private
-
-
# Decodes a Base64 string from the "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=" format
-
#
-
# Example:
-
#
-
# Encodings.b_value_decode("=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=")
-
# #=> 'This is あ string'
-
1
def Encodings.b_value_decode(str)
-
RubyVer.b_value_decode(str)
-
end
-
-
# Decodes a Quoted-Printable string from the "=?UTF-8?Q?This_is_=E3=81=82_string?=" format
-
#
-
# Example:
-
#
-
# Encodings.q_value_decode("=?UTF-8?Q?This_is_=E3=81=82_string?=")
-
# #=> 'This is あ string'
-
1
def Encodings.q_value_decode(str)
-
RubyVer.q_value_decode(str)
-
end
-
-
1
def Encodings.split_encoding_from_string( str )
-
match = str.match(/\=\?([^?]+)?\?[QB]\?(.+)?\?\=/mi)
-
if match
-
match[1]
-
else
-
nil
-
end
-
end
-
-
1
def Encodings.find_encoding(str)
-
RUBY_VERSION >= '1.9' ? str.encoding : $KCODE
-
end
-
-
# Gets the encoding type (Q or B) from the string.
-
1
def Encodings.split_value_encoding_from_string(str)
-
match = str.match(/\=\?[^?]+?\?([QB])\?(.+)?\?\=/mi)
-
if match
-
match[1]
-
else
-
nil
-
end
-
end
-
-
# When the encoded string consists of multiple lines, lines with the same
-
# encoding (Q or B) can be joined together.
-
#
-
# String has to be of the format =?<encoding>?[QB]?<string>?=
-
1
def Encodings.collapse_adjacent_encodings(str)
-
lines = str.split(/(\?=)\s*(=\?)/).each_slice(2).map(&:join)
-
results = []
-
previous_encoding = nil
-
-
lines.each do |line|
-
encoding = split_value_encoding_from_string(line)
-
-
if encoding == previous_encoding
-
line = results.pop + line
-
line.gsub!(/\?\=\=\?.+?\?[QqBb]\?/m, '')
-
end
-
-
previous_encoding = encoding
-
results << line
-
end
-
-
results
-
end
-
end
-
end
-
# encoding: utf-8
-
1
require 'mail/encodings/8bit'
-
-
1
module Mail
-
1
module Encodings
-
1
class SevenBit < EightBit
-
1
NAME = '7bit'
-
-
1
PRIORITY = 1
-
-
# 7bit and 8bit operate the same
-
-
# Decode the string
-
1
def self.decode(str)
-
1
super
-
end
-
-
# Encode the string
-
1
def self.encode(str)
-
1
super
-
end
-
-
# Idenity encodings have a fixed cost, 1 byte out per 1 byte in
-
1
def self.cost(str)
-
super
-
end
-
-
1
Encodings.register(NAME, self)
-
end
-
end
-
end
-
# encoding: utf-8
-
1
require 'mail/encodings/binary'
-
-
1
module Mail
-
1
module Encodings
-
1
class EightBit < Binary
-
1
NAME = '8bit'
-
-
1
PRIORITY = 4
-
-
# 8bit is an identiy encoding, meaning nothing to do
-
-
# Decode the string
-
1
def self.decode(str)
-
1
str.to_lf
-
end
-
-
# Encode the string
-
1
def self.encode(str)
-
1
str.to_crlf
-
end
-
-
# Idenity encodings have a fixed cost, 1 byte out per 1 byte in
-
1
def self.cost(str)
-
1.0
-
end
-
-
1
Encodings.register(NAME, self)
-
end
-
end
-
end
-
# encoding: utf-8
-
1
require 'mail/encodings/7bit'
-
-
1
module Mail
-
1
module Encodings
-
1
class Base64 < SevenBit
-
1
NAME = 'base64'
-
-
1
PRIORITY = 3
-
-
1
def self.can_encode?(enc)
-
true
-
end
-
-
# Decode the string from Base64
-
1
def self.decode(str)
-
RubyVer.decode_base64( str )
-
end
-
-
# Encode the string to Base64
-
1
def self.encode(str)
-
RubyVer.encode_base64( str ).to_crlf
-
end
-
-
# Base64 has a fixed cost, 4 bytes out per 3 bytes in
-
1
def self.cost(str)
-
4.0/3
-
end
-
-
1
Encodings.register(NAME, self)
-
end
-
end
-
end
-
# encoding: utf-8
-
1
require 'mail/encodings/transfer_encoding'
-
-
1
module Mail
-
1
module Encodings
-
1
class Binary < TransferEncoding
-
1
NAME = 'binary'
-
-
1
PRIORITY = 5
-
-
# Binary is an identiy encoding, meaning nothing to do
-
-
# Decode the string
-
1
def self.decode(str)
-
str
-
end
-
-
# Encode the string
-
1
def self.encode(str)
-
str
-
end
-
-
# Idenity encodings have a fixed cost, 1 byte out per 1 byte in
-
1
def self.cost(str)
-
1.0
-
end
-
-
1
Encodings.register(NAME, self)
-
end
-
end
-
end
-
# encoding: utf-8
-
1
require 'mail/encodings/7bit'
-
-
1
module Mail
-
1
module Encodings
-
1
class QuotedPrintable < SevenBit
-
1
NAME='quoted-printable'
-
-
1
PRIORITY = 2
-
-
1
def self.can_encode?(str)
-
EightBit.can_encode? str
-
end
-
-
# Decode the string from Quoted-Printable. Cope with hard line breaks
-
# that were incorrectly encoded as hex instead of literal CRLF.
-
1
def self.decode(str)
-
str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first.to_lf
-
end
-
-
1
def self.encode(str)
-
[str.to_lf].pack("M").to_crlf
-
end
-
-
1
def self.cost(str)
-
# These bytes probably do not need encoding
-
c = str.count("\x9\xA\xD\x20-\x3C\x3E-\x7E")
-
# Everything else turns into =XX where XX is a
-
# two digit hex number (taking 3 bytes)
-
total = (str.bytesize - c)*3 + c
-
total.to_f/str.bytesize
-
end
-
-
1
private
-
-
1
Encodings.register(NAME, self)
-
end
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
module Encodings
-
1
class TransferEncoding
-
1
NAME = ''
-
-
1
PRIORITY = -1
-
-
1
def self.can_transport?(enc)
-
1
enc = Encodings.get_name(enc)
-
1
if Encodings.defined? enc
-
1
Encodings.get_encoding(enc).new.is_a? self
-
else
-
false
-
end
-
end
-
-
1
def self.can_encode?(enc)
-
can_transport? enc
-
end
-
-
1
def self.cost(str)
-
raise "Unimplemented"
-
end
-
-
1
def self.to_s
-
self::NAME
-
end
-
-
1
def self.get_best_compatible(source_encoding, str)
-
1
if self.can_transport? source_encoding then
-
1
source_encoding
-
else
-
choices = []
-
Encodings.get_all.each do |enc|
-
choices << enc if self.can_transport? enc and enc.can_encode? source_encoding
-
end
-
best = nil
-
best_cost = 100
-
choices.each do |enc|
-
this_cost = enc.cost str
-
if this_cost < best_cost then
-
best_cost = this_cost
-
best = enc
-
elsif this_cost == best_cost then
-
best = enc if enc::PRIORITY < best::PRIORITY
-
end
-
end
-
best
-
end
-
end
-
-
1
def to_s
-
self.class.to_s
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Mail Envelope
-
#
-
# The Envelope class provides a field for the first line in an
-
# mbox file, that looks like "From mikel@test.lindsaar.net DATETIME"
-
#
-
# This envelope class reads that line, and turns it into an
-
# Envelope.from and Envelope.date for your use.
-
1
module Mail
-
1
class Envelope < StructuredField
-
-
1
def initialize(*args)
-
super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
-
end
-
-
1
def tree
-
@element ||= Mail::EnvelopeFromElement.new(value)
-
@tree ||= @element.tree
-
end
-
-
1
def element
-
@element ||= Mail::EnvelopeFromElement.new(value)
-
end
-
-
1
def date
-
::DateTime.parse("#{element.date_time}")
-
end
-
-
1
def from
-
element.address
-
end
-
-
end
-
end
-
1
require 'mail/fields'
-
-
# encoding: utf-8
-
1
module Mail
-
# Provides a single class to call to create a new structured or unstructured
-
# field. Works out per RFC what field of field it is being given and returns
-
# the correct field of class back on new.
-
#
-
# ===Per RFC 2822
-
#
-
# 2.2. Header Fields
-
#
-
# Header fields are lines composed of a field name, followed by a colon
-
# (":"), followed by a field body, and terminated by CRLF. A field
-
# name MUST be composed of printable US-ASCII characters (i.e.,
-
# characters that have values between 33 and 126, inclusive), except
-
# colon. A field body may be composed of any US-ASCII characters,
-
# except for CR and LF. However, a field body may contain CRLF when
-
# used in header "folding" and "unfolding" as described in section
-
# 2.2.3. All field bodies MUST conform to the syntax described in
-
# sections 3 and 4 of this standard.
-
#
-
1
class Field
-
-
1
include Patterns
-
1
include Comparable
-
-
1
STRUCTURED_FIELDS = %w[ bcc cc content-description content-disposition
-
content-id content-location content-transfer-encoding
-
content-type date from in-reply-to keywords message-id
-
mime-version received references reply-to
-
resent-bcc resent-cc resent-date resent-from
-
resent-message-id resent-sender resent-to
-
return-path sender to ]
-
-
1
KNOWN_FIELDS = STRUCTURED_FIELDS + ['comments', 'subject']
-
-
1
FIELDS_MAP = {
-
"to" => ToField,
-
"cc" => CcField,
-
"bcc" => BccField,
-
"message-id" => MessageIdField,
-
"in-reply-to" => InReplyToField,
-
"references" => ReferencesField,
-
"subject" => SubjectField,
-
"comments" => CommentsField,
-
"keywords" => KeywordsField,
-
"date" => DateField,
-
"from" => FromField,
-
"sender" => SenderField,
-
"reply-to" => ReplyToField,
-
"resent-date" => ResentDateField,
-
"resent-from" => ResentFromField,
-
"resent-sender" => ResentSenderField,
-
"resent-to" => ResentToField,
-
"resent-cc" => ResentCcField,
-
"resent-bcc" => ResentBccField,
-
"resent-message-id" => ResentMessageIdField,
-
"return-path" => ReturnPathField,
-
"received" => ReceivedField,
-
"mime-version" => MimeVersionField,
-
"content-transfer-encoding" => ContentTransferEncodingField,
-
"content-description" => ContentDescriptionField,
-
"content-disposition" => ContentDispositionField,
-
"content-type" => ContentTypeField,
-
"content-id" => ContentIdField,
-
"content-location" => ContentLocationField,
-
}
-
-
# Generic Field Exception
-
1
class FieldError < StandardError
-
end
-
-
# Raised when a parsing error has occurred (ie, a StructuredField has tried
-
# to parse a field that is invalid or improperly written)
-
1
class ParseError < FieldError #:nodoc:
-
1
attr_accessor :element, :value, :reason
-
-
1
def initialize(element, value, reason)
-
@element = element
-
@value = value
-
@reason = reason
-
super("#{element} can not parse |#{value}|\nReason was: #{reason}")
-
end
-
end
-
-
# Raised when attempting to set a structured field's contents to an invalid syntax
-
1
class SyntaxError < FieldError #:nodoc:
-
end
-
-
# Accepts a string:
-
#
-
# Field.new("field-name: field data")
-
#
-
# Or name, value pair:
-
#
-
# Field.new("field-name", "value")
-
#
-
# Or a name by itself:
-
#
-
# Field.new("field-name")
-
#
-
# Note, does not want a terminating carriage return. Returns
-
# self appropriately parsed. If value is not a string, then
-
# it will be passed through as is, for example, content-type
-
# field can accept an array with the type and a hash of
-
# parameters:
-
#
-
# Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
-
1
def initialize(name, value = nil, charset = 'utf-8')
-
case
-
when name =~ /:/ # Field.new("field-name: field data")
-
charset = value unless value.blank?
-
name, value = split(name)
-
create_field(name, value, charset)
-
when name !~ /:/ && value.blank? # Field.new("field-name")
-
create_field(name, nil, charset)
-
else # Field.new("field-name", "value")
-
14
create_field(name, value, charset)
-
14
end
-
14
return self
-
end
-
-
1
def field=(value)
-
16
@field = value
-
end
-
-
1
def field
-
317
@field
-
end
-
-
1
def name
-
36
field.name
-
end
-
-
1
def value
-
field.value
-
end
-
-
1
def value=(val)
-
create_field(name, val, charset)
-
end
-
-
1
def to_s
-
field.to_s
-
end
-
-
1
def update(name, value)
-
2
create_field(name, value, charset)
-
end
-
-
1
def same( other )
-
22
match_to_s(other.name, field.name)
-
end
-
-
1
alias_method :==, :same
-
-
1
def <=>( other )
-
22
self.field_order_id <=> other.field_order_id
-
end
-
-
1
def field_order_id
-
44
@field_order_id ||= (FIELD_ORDER_LOOKUP[self.name.to_s.downcase] || 100)
-
end
-
-
1
def method_missing(name, *args, &block)
-
259
field.send(name, *args, &block)
-
end
-
-
1
FIELD_ORDER = %w[ return-path received
-
resent-date resent-from resent-sender resent-to
-
resent-cc resent-bcc resent-message-id
-
date from sender reply-to to cc bcc
-
message-id in-reply-to references
-
subject comments keywords
-
mime-version content-type content-transfer-encoding
-
content-location content-disposition content-description ]
-
-
1
FIELD_ORDER_LOOKUP = Hash[FIELD_ORDER.each_with_index.to_a]
-
-
1
private
-
-
1
def split(raw_field)
-
match_data = raw_field.mb_chars.match(FIELD_SPLIT)
-
[match_data[1].to_s.mb_chars.strip, match_data[2].to_s.mb_chars.strip]
-
rescue
-
STDERR.puts "WARNING: Could not parse (and so ignoring) '#{raw_field}'"
-
end
-
-
1
def create_field(name, value, charset)
-
16
begin
-
16
self.field = new_field(name, value, charset)
-
rescue Mail::Field::ParseError => e
-
self.field = Mail::UnstructuredField.new(name, value)
-
self.field.errors << [name, value, e]
-
self.field
-
end
-
end
-
-
1
def new_field(name, value, charset)
-
16
lower_case_name = name.to_s.downcase
-
16
if field_klass = FIELDS_MAP[lower_case_name]
-
16
field_klass.new(value, charset)
-
else
-
OptionalField.new(name, value, charset)
-
end
-
end
-
-
end
-
-
end
-
# encoding: utf-8
-
1
module Mail
-
-
# Field List class provides an enhanced array that keeps a list of
-
# email fields in order. And allows you to insert new fields without
-
# having to worry about the order they will appear in.
-
1
class FieldList < Array
-
-
1
include Enumerable
-
-
1
def <<( new_field )
-
14
current_entry = self.rindex(new_field)
-
14
if current_entry
-
self.insert((current_entry + 1), new_field)
-
else
-
14
insert_idx = -1
-
14
self.each_with_index do |item, idx|
-
22
case item <=> new_field
-
when -1
-
14
next
-
when 0
-
next
-
when 1
-
8
insert_idx = idx
-
8
break
-
end
-
end
-
14
insert(insert_idx, new_field)
-
end
-
end
-
-
end
-
end
-
1
module Mail
-
1
register_autoload :UnstructuredField, 'mail/fields/unstructured_field'
-
1
register_autoload :StructuredField, 'mail/fields/structured_field'
-
1
register_autoload :OptionalField, 'mail/fields/optional_field'
-
-
1
register_autoload :BccField, 'mail/fields/bcc_field'
-
1
register_autoload :CcField, 'mail/fields/cc_field'
-
1
register_autoload :CommentsField, 'mail/fields/comments_field'
-
1
register_autoload :ContentDescriptionField, 'mail/fields/content_description_field'
-
1
register_autoload :ContentDispositionField, 'mail/fields/content_disposition_field'
-
1
register_autoload :ContentIdField, 'mail/fields/content_id_field'
-
1
register_autoload :ContentLocationField, 'mail/fields/content_location_field'
-
1
register_autoload :ContentTransferEncodingField, 'mail/fields/content_transfer_encoding_field'
-
1
register_autoload :ContentTypeField, 'mail/fields/content_type_field'
-
1
register_autoload :DateField, 'mail/fields/date_field'
-
1
register_autoload :FromField, 'mail/fields/from_field'
-
1
register_autoload :InReplyToField, 'mail/fields/in_reply_to_field'
-
1
register_autoload :KeywordsField, 'mail/fields/keywords_field'
-
1
register_autoload :MessageIdField, 'mail/fields/message_id_field'
-
1
register_autoload :MimeVersionField, 'mail/fields/mime_version_field'
-
1
register_autoload :ReceivedField, 'mail/fields/received_field'
-
1
register_autoload :ReferencesField, 'mail/fields/references_field'
-
1
register_autoload :ReplyToField, 'mail/fields/reply_to_field'
-
1
register_autoload :ResentBccField, 'mail/fields/resent_bcc_field'
-
1
register_autoload :ResentCcField, 'mail/fields/resent_cc_field'
-
1
register_autoload :ResentDateField, 'mail/fields/resent_date_field'
-
1
register_autoload :ResentFromField, 'mail/fields/resent_from_field'
-
1
register_autoload :ResentMessageIdField, 'mail/fields/resent_message_id_field'
-
1
register_autoload :ResentSenderField, 'mail/fields/resent_sender_field'
-
1
register_autoload :ResentToField, 'mail/fields/resent_to_field'
-
1
register_autoload :ReturnPathField, 'mail/fields/return_path_field'
-
1
register_autoload :SenderField, 'mail/fields/sender_field'
-
1
register_autoload :SubjectField, 'mail/fields/subject_field'
-
1
register_autoload :ToField, 'mail/fields/to_field'
-
end
-
# encoding: utf-8
-
#
-
# = Blind Carbon Copy Field
-
#
-
# The Bcc field inherits from StructuredField and handles the Bcc: header
-
# field in the email.
-
#
-
# Sending bcc to a mail message will instantiate a Mail::Field object that
-
# has a BccField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one Bcc field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.bcc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:bcc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
-
# mail['bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
-
# mail['Bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
-
#
-
# mail[:bcc].encoded #=> '' # Bcc field does not get output into an email
-
# mail[:bcc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail[:bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:bcc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class BccField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'bcc'
-
1
CAPITALIZED_FIELD = 'Bcc'
-
-
1
def initialize(value = '', charset = 'utf-8')
-
@charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
# Bcc field should never be :encoded
-
1
def encoded
-
''
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Carbon Copy Field
-
#
-
# The Cc field inherits from StructuredField and handles the Cc: header
-
# field in the email.
-
#
-
# Sending cc to a mail message will instantiate a Mail::Field object that
-
# has a CcField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one Cc field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.cc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:cc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
-
# mail['cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
-
# mail['Cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
-
#
-
# mail[:cc].encoded #=> 'Cc: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
-
# mail[:cc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail[:cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:cc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class CcField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'cc'
-
1
CAPITALIZED_FIELD = 'Cc'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Comments Field
-
#
-
# The Comments field inherits from UnstructuredField and handles the Comments:
-
# header field in the email.
-
#
-
# Sending comments to a mail message will instantiate a Mail::Field object that
-
# has a CommentsField as its field type.
-
#
-
# An email header can have as many comments fields as it wants. There is no upper
-
# limit, the comments field is also optional (that is, no comment is needed)
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.comments = 'This is a comment'
-
# mail.comments #=> 'This is a comment'
-
# mail[:comments] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
-
# mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
-
# mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
-
#
-
# mail.comments = "This is another comment"
-
# mail[:comments].map { |c| c.to_s }
-
# #=> ['This is a comment', "This is another comment"]
-
#
-
1
module Mail
-
1
class CommentsField < UnstructuredField
-
-
1
FIELD_NAME = 'comments'
-
1
CAPITALIZED_FIELD = 'Comments'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
@charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value))
-
self.parse
-
self
-
end
-
-
end
-
end
-
1
module Mail
-
-
1
class AddressContainer < Array
-
-
1
def initialize(field, list = [])
-
2
@field = field
-
2
super(list)
-
end
-
-
1
def << (address)
-
@field << address
-
end
-
-
end
-
-
end
-
# encoding: utf-8
-
1
require 'mail/fields/common/address_container'
-
-
1
module Mail
-
1
module CommonAddress # :nodoc:
-
-
1
def parse(val = value)
-
8
unless val.blank?
-
8
@tree = AddressList.new(encode_if_needed(val))
-
else
-
nil
-
end
-
end
-
-
1
def charset
-
8
@charset
-
end
-
-
1
def encode_if_needed(val)
-
8
Encodings.address_encode(val, charset)
-
end
-
-
# Allows you to iterate through each address object in the syntax tree
-
1
def each
-
tree.addresses.each do |address|
-
yield(address)
-
end
-
end
-
-
# Returns the address string of all the addresses in the address list
-
1
def addresses
-
4
list = tree.addresses.map { |a| a.address }
-
2
Mail::AddressContainer.new(self, list)
-
end
-
-
# Returns the formatted string of all the addresses in the address list
-
1
def formatted
-
list = tree.addresses.map { |a| a.format }
-
Mail::AddressContainer.new(self, list)
-
end
-
-
# Returns the display name of all the addresses in the address list
-
1
def display_names
-
list = tree.addresses.map { |a| a.display_name }
-
Mail::AddressContainer.new(self, list)
-
end
-
-
# Returns the actual address objects in the address list
-
1
def addrs
-
list = tree.addresses
-
Mail::AddressContainer.new(self, list)
-
end
-
-
# Returns a hash of group name => address strings for the address list
-
1
def groups
-
@groups = Hash.new
-
tree.group_recipients.each do |group|
-
@groups[group.group_name.text_value.to_str] = get_group_addresses(group.group_list)
-
end
-
@groups
-
end
-
-
# Returns the addresses that are part of groups
-
1
def group_addresses
-
decoded_group_addresses
-
end
-
-
# Returns a list of decoded group addresses
-
1
def decoded_group_addresses
-
groups.map { |k,v| v.map { |a| a.decoded } }.flatten
-
end
-
-
# Returns a list of encoded group addresses
-
1
def encoded_group_addresses
-
groups.map { |k,v| v.map { |a| a.encoded } }.flatten
-
end
-
-
# Returns the name of all the groups in a string
-
1
def group_names # :nodoc:
-
tree.group_names
-
end
-
-
1
def default
-
2
addresses
-
end
-
-
1
def <<(val)
-
case
-
when val.nil?
-
raise ArgumentError, "Need to pass an address to <<"
-
when val.blank?
-
parse(encoded)
-
else
-
self.value = [self.value, val].reject {|a| a.blank? }.join(", ")
-
end
-
end
-
-
1
def value=(val)
-
4
super
-
4
parse(self.value)
-
end
-
-
1
private
-
-
1
def do_encode(field_name)
-
return '' if value.blank?
-
address_array = tree.addresses.reject { |a| encoded_group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded }
-
address_text = address_array.join(", \r\n\s")
-
group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.encoded }.join(", \r\n\s")};" }
-
group_text = group_array.join(" \r\n\s")
-
return_array = [address_text, group_text].reject { |a| a.blank? }
-
"#{field_name}: #{return_array.join(", \r\n\s")}\r\n"
-
end
-
-
1
def do_decode
-
return nil if value.blank?
-
address_array = tree.addresses.reject { |a| decoded_group_addresses.include?(a.decoded) }.map { |a| a.decoded }
-
address_text = address_array.join(", ")
-
group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.decoded }.join(", ")};" }
-
group_text = group_array.join(" ")
-
return_array = [address_text, group_text].reject { |a| a.blank? }
-
return_array.join(", ")
-
end
-
-
# Returns the syntax tree of the Addresses
-
1
def tree # :nodoc:
-
2
@tree ||= AddressList.new(value)
-
end
-
-
1
def get_group_addresses(group_list)
-
if group_list.respond_to?(:addresses)
-
group_list.addresses.map do |address_tree|
-
Mail::Address.new(address_tree)
-
end
-
else
-
[]
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
module CommonDate # :nodoc:
-
# Returns a date time object of the parsed date
-
1
def date_time
-
::DateTime.parse("#{element.date_string} #{element.time_string}")
-
end
-
-
1
def default
-
date_time
-
end
-
-
1
def parse(val = value)
-
unless val.blank?
-
@element = Mail::DateTimeElement.new(val)
-
@tree = @element.tree
-
else
-
nil
-
end
-
end
-
-
1
private
-
-
1
def do_encode(field_name)
-
"#{field_name}: #{value}\r\n"
-
end
-
-
1
def do_decode
-
"#{value}"
-
end
-
-
1
def element
-
@element ||= Mail::DateTimeElement.new(value)
-
end
-
-
# Returns the syntax tree of the Date
-
1
def tree
-
@tree ||= element.tree
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
module CommonField # :nodoc:
-
-
1
def name=(value)
-
16
@name = value
-
end
-
-
1
def name
-
264
@name ||= nil
-
end
-
-
1
def value=(value)
-
22
@length = nil
-
22
@tree = nil
-
22
@element = nil
-
22
@value = value
-
end
-
-
1
def value
-
14
@value
-
end
-
-
1
def to_s
-
decoded.to_s
-
end
-
-
1
def default
-
decoded
-
end
-
-
1
def field_length
-
@length ||= "#{name}: #{encode(decoded)}".length
-
end
-
-
1
def responsible_for?( val )
-
206
name.to_s.casecmp(val.to_s) == 0
-
end
-
-
1
private
-
-
1
def strip_field(field_name, value)
-
14
if value.is_a?(Array)
-
value
-
else
-
14
value.to_s.gsub(/#{field_name}:\s+/i, '')
-
end
-
end
-
-
1
FILENAME_RE = /\b(filename|name)=([^;"\r\n]+\s[^;"\r\n]+)/
-
1
def ensure_filename_quoted(value)
-
6
if value.is_a?(String)
-
4
value.sub! FILENAME_RE, '\1="\2"'
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
module CommonMessageId # :nodoc:
-
1
def element
-
@element ||= Mail::MessageIdsElement.new(value) unless value.blank?
-
end
-
-
1
def parse(val = value)
-
unless val.blank?
-
@element = Mail::MessageIdsElement.new(val)
-
else
-
nil
-
end
-
end
-
-
1
def message_id
-
element.message_id if element
-
end
-
-
1
def message_ids
-
element.message_ids if element
-
end
-
-
1
def default
-
return nil unless message_ids
-
if message_ids.length == 1
-
message_ids[0]
-
else
-
message_ids
-
end
-
end
-
-
1
private
-
-
1
def do_encode(field_name)
-
%Q{#{field_name}: #{formated_message_ids("\r\n ")}\r\n}
-
end
-
-
1
def do_decode
-
formated_message_ids(' ')
-
end
-
-
1
def formated_message_ids(join)
-
message_ids.map{ |m| "<#{m}>" }.join(join) if message_ids
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
-
# ParameterHash is an intelligent Hash that allows you to add
-
# parameter values including the MIME extension paramaters that
-
# have the name*0="blah", name*1="bleh" keys, and will just return
-
# a single key called name="blahbleh" and do any required un-encoding
-
# to make that happen
-
# Parameters are defined in RFC2045, split keys are in RFC2231
-
-
1
class ParameterHash < IndifferentHash
-
-
1
include Mail::Utilities
-
-
1
def [](key_name)
-
6
key_pattern = Regexp.escape(key_name.to_s)
-
6
pairs = []
-
6
exact = nil
-
6
each do |k,v|
-
2
if k =~ /^#{key_pattern}(\*|$)/i
-
2
if $1 == '*'
-
pairs << [k, v]
-
else
-
2
exact = k
-
end
-
end
-
end
-
6
if pairs.empty? # Just dealing with a single value pair
-
6
super(exact || key_name)
-
else # Dealing with a multiple value pair or a single encoded value pair
-
string = pairs.sort { |a,b| a.first.to_s <=> b.first.to_s }.map { |v| v.last }.join('')
-
if mt = string.match(/([\w\-]+)'(\w\w)'(.*)/)
-
string = mt[3]
-
encoding = mt[1]
-
else
-
encoding = nil
-
end
-
Mail::Encodings.param_decode(string, encoding)
-
end
-
end
-
-
1
def encoded
-
map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value|
-
unless value.ascii_only?
-
value = Mail::Encodings.param_encode(value)
-
key_name = "#{key_name}*"
-
end
-
%Q{#{key_name}=#{quote_token(value)}}
-
end.join(";\r\n\s")
-
end
-
-
1
def decoded
-
map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value|
-
%Q{#{key_name}=#{quote_token(value)}}
-
end.join("; ")
-
end
-
end
-
end
-
# encoding: utf-8
-
#
-
#
-
#
-
1
module Mail
-
1
class ContentDescriptionField < UnstructuredField
-
-
1
FIELD_NAME = 'content-description'
-
1
CAPITALIZED_FIELD = 'Content-Description'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
require 'mail/fields/common/parameter_hash'
-
-
1
module Mail
-
1
class ContentDispositionField < StructuredField
-
-
1
FIELD_NAME = 'content-disposition'
-
1
CAPITALIZED_FIELD = 'Content-Disposition'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
ensure_filename_quoted(value)
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def parse(val = value)
-
unless val.blank?
-
@element = Mail::ContentDispositionElement.new(val)
-
end
-
end
-
-
1
def element
-
@element ||= Mail::ContentDispositionElement.new(value)
-
end
-
-
1
def disposition_type
-
element.disposition_type
-
end
-
-
1
def parameters
-
@parameters = ParameterHash.new
-
element.parameters.each { |p| @parameters.merge!(p) }
-
@parameters
-
end
-
-
1
def filename
-
case
-
when !parameters['filename'].blank?
-
@filename = parameters['filename']
-
when !parameters['name'].blank?
-
@filename = parameters['name']
-
else
-
@filename = nil
-
end
-
@filename
-
end
-
-
# TODO: Fix this up
-
1
def encoded
-
if parameters.length > 0
-
p = ";\r\n\s#{parameters.encoded}\r\n"
-
else
-
p = "\r\n"
-
end
-
"#{CAPITALIZED_FIELD}: #{disposition_type}" + p
-
end
-
-
1
def decoded
-
if parameters.length > 0
-
p = "; #{parameters.decoded}"
-
else
-
p = ""
-
end
-
"#{disposition_type}" + p
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
#
-
#
-
1
module Mail
-
1
class ContentIdField < StructuredField
-
-
1
FIELD_NAME = 'content-id'
-
1
CAPITALIZED_FIELD = "Content-ID"
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
@uniq = 1
-
if value.blank?
-
value = generate_content_id
-
else
-
value = strip_field(FIELD_NAME, value)
-
end
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def parse(val = value)
-
unless val.blank?
-
@element = Mail::MessageIdsElement.new(val)
-
end
-
end
-
-
1
def element
-
@element ||= Mail::MessageIdsElement.new(value)
-
end
-
-
1
def name
-
'Content-ID'
-
end
-
-
1
def content_id
-
element.message_id
-
end
-
-
1
def to_s
-
"<#{content_id}>"
-
end
-
-
# TODO: Fix this up
-
1
def encoded
-
"#{CAPITALIZED_FIELD}: #{to_s}\r\n"
-
end
-
-
1
def decoded
-
"#{to_s}"
-
end
-
-
1
private
-
-
1
def generate_content_id
-
"<#{Mail.random_tag}@#{::Socket.gethostname}.mail>"
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
#
-
#
-
1
module Mail
-
1
class ContentLocationField < StructuredField
-
-
1
FIELD_NAME = 'content-location'
-
1
CAPITALIZED_FIELD = 'Content-Location'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def parse(val = value)
-
unless val.blank?
-
@element = Mail::ContentLocationElement.new(val)
-
end
-
end
-
-
1
def element
-
@element ||= Mail::ContentLocationElement.new(value)
-
end
-
-
1
def location
-
element.location
-
end
-
-
# TODO: Fix this up
-
1
def encoded
-
"#{CAPITALIZED_FIELD}: #{location}\r\n"
-
end
-
-
1
def decoded
-
location
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
#
-
#
-
1
module Mail
-
1
class ContentTransferEncodingField < StructuredField
-
-
1
FIELD_NAME = 'content-transfer-encoding'
-
1
CAPITALIZED_FIELD = 'Content-Transfer-Encoding'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
value = '7bit' if value.to_s =~ /7-?bits?/i
-
value = '8bit' if value.to_s =~ /8-?bits?/i
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def parse(val = value)
-
unless val.blank?
-
@element = Mail::ContentTransferEncodingElement.new(val)
-
end
-
end
-
-
1
def tree
-
STDERR.puts("tree is deprecated. Please use encoding to get parse result\n#{caller}")
-
@element ||= Mail::ContentTransferEncodingElement.new(value)
-
@tree ||= @element.tree
-
end
-
-
1
def element
-
@element ||= Mail::ContentTransferEncodingElement.new(value)
-
end
-
-
1
def encoding
-
element.encoding
-
end
-
-
# TODO: Fix this up
-
1
def encoded
-
"#{CAPITALIZED_FIELD}: #{encoding}\r\n"
-
end
-
-
1
def decoded
-
encoding
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
require 'mail/fields/common/parameter_hash'
-
-
1
module Mail
-
1
class ContentTypeField < StructuredField
-
-
1
FIELD_NAME = 'content-type'
-
1
CAPITALIZED_FIELD = 'Content-Type'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
6
self.charset = charset
-
6
if value.class == Array
-
2
@main_type = value[0]
-
2
@sub_type = value[1]
-
2
@parameters = ParameterHash.new.merge!(value.last)
-
else
-
4
@main_type = nil
-
4
@sub_type = nil
-
4
@parameters = nil
-
4
value = strip_field(FIELD_NAME, value)
-
end
-
6
ensure_filename_quoted(value)
-
6
super(CAPITALIZED_FIELD, value, charset)
-
6
self.parse
-
6
self
-
end
-
-
1
def parse(val = value)
-
6
unless val.blank?
-
6
self.value = val
-
6
@element = nil
-
6
element
-
end
-
end
-
-
1
def element
-
16
begin
-
16
@element ||= Mail::ContentTypeElement.new(value)
-
rescue
-
attempt_to_clean
-
end
-
end
-
-
1
def attempt_to_clean
-
# Sanitize the value, handle special cases
-
@element ||= Mail::ContentTypeElement.new(sanatize(value))
-
rescue
-
# All else fails, just get the MIME media type
-
@element ||= Mail::ContentTypeElement.new(get_mime_type(value))
-
end
-
-
1
def main_type
-
16
@main_type ||= element.main_type
-
end
-
-
1
def sub_type
-
2
@sub_type ||= element.sub_type
-
end
-
-
1
def string
-
2
"#{main_type}/#{sub_type}"
-
end
-
-
1
def default
-
2
decoded
-
end
-
-
1
alias :content_type :string
-
-
1
def parameters
-
14
unless @parameters
-
4
@parameters = ParameterHash.new
-
4
element.parameters.each { |p| @parameters.merge!(p) }
-
end
-
14
@parameters
-
end
-
-
1
def ContentTypeField.with_boundary(type)
-
new("#{type}; boundary=#{generate_boundary}")
-
end
-
-
1
def ContentTypeField.generate_boundary
-
"--==_mimepart_#{Mail.random_tag}"
-
end
-
-
1
def value
-
12
if @value.class == Array
-
2
"#{@main_type}/#{@sub_type}; #{stringify(parameters)}"
-
else
-
10
@value
-
end
-
end
-
-
1
def stringify(params)
-
4
params.map { |k,v| "#{k}=#{Encodings.param_encode(v)}" }.join("; ")
-
end
-
-
1
def filename
-
case
-
when parameters['filename']
-
@filename = parameters['filename']
-
when parameters['name']
-
@filename = parameters['name']
-
else
-
@filename = nil
-
end
-
@filename
-
end
-
-
# TODO: Fix this up
-
1
def encoded
-
if parameters.length > 0
-
p = ";\r\n\s#{parameters.encoded}"
-
else
-
p = ""
-
end
-
"#{CAPITALIZED_FIELD}: #{content_type}#{p}\r\n"
-
end
-
-
1
def decoded
-
2
if parameters.length > 0
-
p = "; #{parameters.decoded}"
-
else
-
2
p = ""
-
end
-
2
"#{content_type}" + p
-
end
-
-
1
private
-
-
1
def method_missing(name, *args, &block)
-
if name.to_s =~ /(\w+)=/
-
self.parameters[$1] = args.first
-
@value = "#{content_type}; #{stringify(parameters)}"
-
else
-
super
-
end
-
end
-
-
# Various special cases from random emails found that I am not going to change
-
# the parser for
-
1
def sanatize( val )
-
-
# TODO: check if there are cases where whitespace is not a separator
-
val = val.
-
gsub(/\s*=\s*/,'='). # remove whitespaces around equal sign
-
tr(' ',';').
-
squeeze(';').
-
gsub(';', '; '). #use '; ' as a separator (or EOL)
-
gsub(/;\s*$/,'') #remove trailing to keep examples below
-
-
if val =~ /(boundary=(\S*))/i
-
val = "#{$`.downcase}boundary=#{$2}#{$'.downcase}"
-
else
-
val.downcase!
-
end
-
-
case
-
when val.chomp =~ /^\s*([\w\-]+)\/([\w\-]+)\s*;;+(.*)$/i
-
# Handles 'text/plain;; format="flowed"' (double semi colon)
-
"#{$1}/#{$2}; #{$3}"
-
when val.chomp =~ /^\s*([\w\-]+)\/([\w\-]+)\s*;\s?(ISO[\w\-]+)$/i
-
# Microsoft helper:
-
# Handles 'type/subtype;ISO-8559-1'
-
"#{$1}/#{$2}; charset=#{quote_atom($3)}"
-
when val.chomp =~ /^text;?$/i
-
# Handles 'text;' and 'text'
-
"text/plain;"
-
when val.chomp =~ /^(\w+);\s(.*)$/i
-
# Handles 'text; <parameters>'
-
"text/plain; #{$2}"
-
when val =~ /([\w\-]+\/[\w\-]+);\scharset="charset="(\w+)""/i
-
# Handles text/html; charset="charset="GB2312""
-
"#{$1}; charset=#{quote_atom($2)}"
-
when val =~ /([\w\-]+\/[\w\-]+);\s+(.*)/i
-
type = $1
-
# Handles misquoted param values
-
# e.g: application/octet-stream; name=archiveshelp1[1].htm
-
# and: audio/x-midi;\r\n\sname=Part .exe
-
params = $2.to_s.split(/\s+/)
-
params = params.map { |i| i.to_s.chomp.strip }
-
params = params.map { |i| i.split(/\s*\=\s*/) }
-
params = params.map { |i| "#{i[0]}=#{dquote(i[1].to_s.gsub(/;$/,""))}" }.join('; ')
-
"#{type}; #{params}"
-
when val =~ /^\s*$/
-
'text/plain'
-
else
-
''
-
end
-
end
-
-
1
def get_mime_type( val )
-
case
-
when val =~ /^([\w\-]+)\/([\w\-]+);.+$/i
-
"#{$1}/#{$2}"
-
else
-
'text/plain'
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Date Field
-
#
-
# The Date field inherits from StructuredField and handles the Date: header
-
# field in the email.
-
#
-
# Sending date to a mail message will instantiate a Mail::Field object that
-
# has a DateField as its field type. This includes all Mail::CommonAddress
-
# module instance methods.
-
#
-
# There must be excatly one Date field in an RFC2822 email.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.date = 'Mon, 24 Nov 1997 14:22:01 -0800'
-
# mail.date #=> #<DateTime: 211747170121/86400,-1/3,2299161>
-
# mail.date.to_s #=> 'Mon, 24 Nov 1997 14:22:01 -0800'
-
# mail[:date] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::DateField:0x180e1c4
-
# mail['date'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::DateField:0x180e1c4
-
# mail['Date'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::DateField:0x180e1c4
-
#
-
1
require 'mail/fields/common/common_date'
-
-
1
module Mail
-
1
class DateField < StructuredField
-
-
1
include Mail::CommonDate
-
-
1
FIELD_NAME = 'date'
-
1
CAPITALIZED_FIELD = "Date"
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
if value.blank?
-
value = ::DateTime.now.strftime('%a, %d %b %Y %H:%M:%S %z')
-
else
-
value = strip_field(FIELD_NAME, value)
-
value.to_s.gsub!(/\(.*?\)/, '')
-
value = ::DateTime.parse(value.to_s.squeeze(" ")).strftime('%a, %d %b %Y %H:%M:%S %z')
-
end
-
super(CAPITALIZED_FIELD, value, charset)
-
rescue ArgumentError => e
-
raise e unless "invalid date"==e.message
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = From Field
-
#
-
# The From field inherits from StructuredField and handles the From: header
-
# field in the email.
-
#
-
# Sending from to a mail message will instantiate a Mail::Field object that
-
# has a FromField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one From field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.from = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:from] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::FromField:0x180e1c4
-
# mail['from'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::FromField:0x180e1c4
-
# mail['From'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::FromField:0x180e1c4
-
#
-
# mail[:from].encoded #=> 'from: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
-
# mail[:from].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail[:from].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:from].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class FromField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'from'
-
1
CAPITALIZED_FIELD = 'From'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
2
self.charset = charset
-
2
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
2
self.parse
-
2
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = In-Reply-To Field
-
#
-
# The In-Reply-To field inherits from StructuredField and handles the
-
# In-Reply-To: header field in the email.
-
#
-
# Sending in_reply_to to a mail message will instantiate a Mail::Field object that
-
# has a InReplyToField as its field type. This includes all Mail::CommonMessageId
-
# module instance metods.
-
#
-
# Note that, the #message_ids method will return an array of message IDs without the
-
# enclosing angle brackets which per RFC are not syntactically part of the message id.
-
#
-
# Only one InReplyTo field can appear in a header, though it can have multiple
-
# Message IDs.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.in_reply_to = '<F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom>'
-
# mail.in_reply_to #=> '<F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom>'
-
# mail[:in_reply_to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::InReplyToField:0x180e1c4
-
# mail['in_reply_to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::InReplyToField:0x180e1c4
-
# mail['In-Reply-To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::InReplyToField:0x180e1c4
-
#
-
# mail[:in_reply_to].message_ids #=> ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom']
-
#
-
1
require 'mail/fields/common/common_message_id'
-
-
1
module Mail
-
1
class InReplyToField < StructuredField
-
-
1
include Mail::CommonMessageId
-
-
1
FIELD_NAME = 'in-reply-to'
-
1
CAPITALIZED_FIELD = 'In-Reply-To'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
value = value.join("\r\n\s") if value.is_a?(Array)
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# keywords = "Keywords:" phrase *("," phrase) CRLF
-
1
module Mail
-
1
class KeywordsField < StructuredField
-
-
1
FIELD_NAME = 'keywords'
-
1
CAPITALIZED_FIELD = 'Keywords'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def parse(val = value)
-
unless val.blank?
-
@phrase_list ||= PhraseList.new(value)
-
end
-
end
-
-
1
def phrase_list
-
@phrase_list ||= PhraseList.new(value)
-
end
-
-
1
def keywords
-
phrase_list.phrases
-
end
-
-
1
def encoded
-
"#{CAPITALIZED_FIELD}: #{keywords.join(",\r\n ")}\r\n"
-
end
-
-
1
def decoded
-
keywords.join(', ')
-
end
-
-
1
def default
-
keywords
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Message-ID Field
-
#
-
# The Message-ID field inherits from StructuredField and handles the
-
# Message-ID: header field in the email.
-
#
-
# Sending message_id to a mail message will instantiate a Mail::Field object that
-
# has a MessageIdField as its field type. This includes all Mail::CommonMessageId
-
# module instance metods.
-
#
-
# Only one MessageId field can appear in a header, and syntactically it can only have
-
# one Message ID. The message_ids method call has been left in however as it will only
-
# return the one message id, ie, an array of length 1.
-
#
-
# Note that, the #message_ids method will return an array of message IDs without the
-
# enclosing angle brackets which per RFC are not syntactically part of the message id.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.message_id = '<F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom>'
-
# mail.message_id #=> '<F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom>'
-
# mail[:message_id] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::MessageIdField:0x180e1c4
-
# mail['message_id'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::MessageIdField:0x180e1c4
-
# mail['Message-ID'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::MessageIdField:0x180e1c4
-
#
-
# mail[:message_id].message_id #=> 'F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom'
-
# mail[:message_id].message_ids #=> ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom']
-
#
-
1
require 'mail/fields/common/common_message_id'
-
-
1
module Mail
-
1
class MessageIdField < StructuredField
-
-
1
include Mail::CommonMessageId
-
-
1
FIELD_NAME = 'message-id'
-
1
CAPITALIZED_FIELD = 'Message-ID'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
@uniq = 1
-
if value.blank?
-
self.name = CAPITALIZED_FIELD
-
self.value = generate_message_id
-
else
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
end
-
self.parse
-
self
-
-
end
-
-
1
def name
-
'Message-ID'
-
end
-
-
1
def message_ids
-
[message_id]
-
end
-
-
1
def to_s
-
"<#{message_id}>"
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
1
private
-
-
1
def generate_message_id
-
"<#{Mail.random_tag}@#{::Socket.gethostname}.mail>"
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
#
-
#
-
1
module Mail
-
1
class MimeVersionField < StructuredField
-
-
1
FIELD_NAME = 'mime-version'
-
1
CAPITALIZED_FIELD = 'Mime-Version'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
4
self.charset = charset
-
4
if value.blank?
-
value = '1.0'
-
end
-
4
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
4
self.parse
-
4
self
-
-
end
-
-
1
def parse(val = value)
-
4
unless val.blank?
-
4
@element = Mail::MimeVersionElement.new(val)
-
end
-
end
-
-
1
def element
-
@element ||= Mail::MimeVersionElement.new(value)
-
end
-
-
1
def version
-
"#{element.major}.#{element.minor}"
-
end
-
-
1
def major
-
element.major.to_i
-
end
-
-
1
def minor
-
element.minor.to_i
-
end
-
-
1
def encoded
-
"#{CAPITALIZED_FIELD}: #{version}\r\n"
-
end
-
-
1
def decoded
-
version
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# trace = [return]
-
# 1*received
-
#
-
# return = "Return-Path:" path CRLF
-
#
-
# path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) /
-
# obs-path
-
#
-
# received = "Received:" name-val-list ";" date-time CRLF
-
#
-
# name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)]
-
#
-
# name-val-pair = item-name CFWS item-value
-
#
-
# item-name = ALPHA *(["-"] (ALPHA / DIGIT))
-
#
-
# item-value = 1*angle-addr / addr-spec /
-
# atom / domain / msg-id
-
#
-
1
module Mail
-
1
class ReceivedField < StructuredField
-
-
1
FIELD_NAME = 'received'
-
1
CAPITALIZED_FIELD = 'Received'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
-
end
-
-
1
def parse(val = value)
-
unless val.blank?
-
@element = Mail::ReceivedElement.new(val)
-
end
-
end
-
-
1
def element
-
@element ||= Mail::ReceivedElement.new(value)
-
end
-
-
1
def date_time
-
@datetime ||= ::DateTime.parse("#{element.date_time}")
-
end
-
-
1
def info
-
element.info
-
end
-
-
1
def formatted_date
-
date_time.strftime("%a, %d %b %Y %H:%M:%S ") + date_time.zone.delete(':')
-
end
-
-
1
def encoded
-
if value.blank?
-
"#{CAPITALIZED_FIELD}: \r\n"
-
else
-
"#{CAPITALIZED_FIELD}: #{info}; #{formatted_date}\r\n"
-
end
-
end
-
-
1
def decoded
-
if value.blank?
-
""
-
else
-
"#{info}; #{formatted_date}"
-
end
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = References Field
-
#
-
# The References field inherits references StructuredField and handles the References: header
-
# field in the email.
-
#
-
# Sending references to a mail message will instantiate a Mail::Field object that
-
# has a ReferencesField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Note that, the #message_ids method will return an array of message IDs without the
-
# enclosing angle brackets which per RFC are not syntactically part of the message id.
-
#
-
# Only one References field can appear in a header, though it can have multiple
-
# Message IDs.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.references = '<F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom>'
-
# mail.references #=> '<F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom>'
-
# mail[:references] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ReferencesField:0x180e1c4
-
# mail['references'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ReferencesField:0x180e1c4
-
# mail['References'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ReferencesField:0x180e1c4
-
#
-
# mail[:references].message_ids #=> ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom']
-
#
-
1
require 'mail/fields/common/common_message_id'
-
-
1
module Mail
-
1
class ReferencesField < StructuredField
-
-
1
include CommonMessageId
-
-
1
FIELD_NAME = 'references'
-
1
CAPITALIZED_FIELD = 'References'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
value = value.join("\r\n\s") if value.is_a?(Array)
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Reply-To Field
-
#
-
# The Reply-To field inherits reply-to StructuredField and handles the Reply-To: header
-
# field in the email.
-
#
-
# Sending reply_to to a mail message will instantiate a Mail::Field object that
-
# has a ReplyToField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one Reply-To field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.reply_to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:reply_to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ReplyToField:0x180e1c4
-
# mail['reply-to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ReplyToField:0x180e1c4
-
# mail['Reply-To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ReplyToField:0x180e1c4
-
#
-
# mail[:reply_to].encoded #=> 'Reply-To: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
-
# mail[:reply_to].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail[:reply_to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:reply_to].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class ReplyToField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'reply-to'
-
1
CAPITALIZED_FIELD = 'Reply-To'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Resent-Bcc Field
-
#
-
# The Resent-Bcc field inherits resent-bcc StructuredField and handles the
-
# Resent-Bcc: header field in the email.
-
#
-
# Sending resent_bcc to a mail message will instantiate a Mail::Field object that
-
# has a ResentBccField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one Resent-Bcc field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.resent_bcc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:resent_bcc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentBccField:0x180e1c4
-
# mail['resent-bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentBccField:0x180e1c4
-
# mail['Resent-Bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentBccField:0x180e1c4
-
#
-
# mail[:resent_bcc].encoded #=> 'Resent-Bcc: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
-
# mail[:resent_bcc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail[:resent_bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:resent_bcc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class ResentBccField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'resent-bcc'
-
1
CAPITALIZED_FIELD = 'Resent-Bcc'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Resent-Cc Field
-
#
-
# The Resent-Cc field inherits resent-cc StructuredField and handles the Resent-Cc: header
-
# field in the email.
-
#
-
# Sending resent_cc to a mail message will instantiate a Mail::Field object that
-
# has a ResentCcField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one Resent-Cc field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.resent_cc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:resent_cc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentCcField:0x180e1c4
-
# mail['resent-cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentCcField:0x180e1c4
-
# mail['Resent-Cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentCcField:0x180e1c4
-
#
-
# mail[:resent_cc].encoded #=> 'Resent-Cc: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
-
# mail[:resent_cc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail[:resent_cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:resent_cc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class ResentCcField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'resent-cc'
-
1
CAPITALIZED_FIELD = 'Resent-Cc'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# resent-date = "Resent-Date:" date-time CRLF
-
1
require 'mail/fields/common/common_date'
-
-
1
module Mail
-
1
class ResentDateField < StructuredField
-
-
1
include Mail::CommonDate
-
-
1
FIELD_NAME = 'resent-date'
-
1
CAPITALIZED_FIELD = 'Resent-Date'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
if value.blank?
-
value = ::DateTime.now.strftime('%a, %d %b %Y %H:%M:%S %z')
-
else
-
value = strip_field(FIELD_NAME, value)
-
value = ::DateTime.parse(value.to_s).strftime('%a, %d %b %Y %H:%M:%S %z')
-
end
-
super(CAPITALIZED_FIELD, value, charset)
-
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Resent-From Field
-
#
-
# The Resent-From field inherits resent-from StructuredField and handles the Resent-From: header
-
# field in the email.
-
#
-
# Sending resent_from to a mail message will instantiate a Mail::Field object that
-
# has a ResentFromField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one Resent-From field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.resent_from = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:resent_from] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentFromField:0x180e1c4
-
# mail['resent-from'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentFromField:0x180e1c4
-
# mail['Resent-From'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentFromField:0x180e1c4
-
#
-
# mail[:resent_from].encoded #=> 'Resent-From: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
-
# mail[:resent_from].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail[:resent_from].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:resent_from].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class ResentFromField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'resent-from'
-
1
CAPITALIZED_FIELD = 'Resent-From'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# resent-msg-id = "Resent-Message-ID:" msg-id CRLF
-
1
require 'mail/fields/common/common_message_id'
-
-
1
module Mail
-
1
class ResentMessageIdField < StructuredField
-
-
1
include CommonMessageId
-
-
1
FIELD_NAME = 'resent-message-id'
-
1
CAPITALIZED_FIELD = 'Resent-Message-ID'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def name
-
'Resent-Message-ID'
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Resent-Sender Field
-
#
-
# The Resent-Sender field inherits resent-sender StructuredField and handles the Resent-Sender: header
-
# field in the email.
-
#
-
# Sending resent_sender to a mail message will instantiate a Mail::Field object that
-
# has a ResentSenderField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one Resent-Sender field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.resent_sender = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_sender #=> ['mikel@test.lindsaar.net']
-
# mail[:resent_sender] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentSenderField:0x180e1c4
-
# mail['resent-sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentSenderField:0x180e1c4
-
# mail['Resent-Sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentSenderField:0x180e1c4
-
#
-
# mail.resent_sender.to_s #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_sender.addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail.resent_sender.formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class ResentSenderField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'resent-sender'
-
1
CAPITALIZED_FIELD = 'Resent-Sender'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def addresses
-
[address.address]
-
end
-
-
1
def address
-
tree.addresses.first
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Resent-To Field
-
#
-
# The Resent-To field inherits resent-to StructuredField and handles the Resent-To: header
-
# field in the email.
-
#
-
# Sending resent_to to a mail message will instantiate a Mail::Field object that
-
# has a ResentToField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one Resent-To field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.resent_to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:resent_to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
-
# mail['resent-to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
-
# mail['Resent-To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
-
#
-
# mail[:resent_to].encoded #=> 'Resent-To: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
-
# mail[:resent_to].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail[:resent_to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:resent_to].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class ResentToField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'resent-to'
-
1
CAPITALIZED_FIELD = 'Resent-To'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# 4.4.3. REPLY-TO / RESENT-REPLY-TO
-
#
-
# Note: The "Return-Path" field is added by the mail transport
-
# service, at the time of final deliver. It is intended
-
# to identify a path back to the orginator of the mes-
-
# sage. The "Reply-To" field is added by the message
-
# originator and is intended to direct replies.
-
#
-
# trace = [return]
-
# 1*received
-
#
-
# return = "Return-Path:" path CRLF
-
#
-
# path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) /
-
# obs-path
-
#
-
# received = "Received:" name-val-list ";" date-time CRLF
-
#
-
# name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)]
-
#
-
# name-val-pair = item-name CFWS item-value
-
#
-
# item-name = ALPHA *(["-"] (ALPHA / DIGIT))
-
#
-
# item-value = 1*angle-addr / addr-spec /
-
# atom / domain / msg-id
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class ReturnPathField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'return-path'
-
1
CAPITALIZED_FIELD = 'Return-Path'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
value = nil if value == '<>'
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def encoded
-
"#{CAPITALIZED_FIELD}: <#{address}>\r\n"
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
1
def address
-
addresses.first
-
end
-
-
1
def default
-
address
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = Sender Field
-
#
-
# The Sender field inherits sender StructuredField and handles the Sender: header
-
# field in the email.
-
#
-
# Sending sender to a mail message will instantiate a Mail::Field object that
-
# has a SenderField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one Sender field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.sender = 'Mikel Lindsaar <mikel@test.lindsaar.net>'
-
# mail.sender #=> 'mikel@test.lindsaar.net'
-
# mail[:sender] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
-
# mail['sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
-
# mail['Sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
-
#
-
# mail[:sender].encoded #=> "Sender: Mikel Lindsaar <mikel@test.lindsaar.net>\r\n"
-
# mail[:sender].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>'
-
# mail[:sender].addresses #=> ['mikel@test.lindsaar.net']
-
# mail[:sender].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class SenderField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'sender'
-
1
CAPITALIZED_FIELD = 'Sender'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
self.charset = charset
-
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
self.parse
-
self
-
end
-
-
1
def addresses
-
[address.address]
-
end
-
-
1
def address
-
tree.addresses.first
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
1
def default
-
address.address
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
require 'mail/fields/common/common_field'
-
-
1
module Mail
-
# Provides access to a structured header field
-
#
-
# ===Per RFC 2822:
-
# 2.2.2. Structured Header Field Bodies
-
#
-
# Some field bodies in this standard have specific syntactical
-
# structure more restrictive than the unstructured field bodies
-
# described above. These are referred to as "structured" field bodies.
-
# Structured field bodies are sequences of specific lexical tokens as
-
# described in sections 3 and 4 of this standard. Many of these tokens
-
# are allowed (according to their syntax) to be introduced or end with
-
# comments (as described in section 3.2.3) as well as the space (SP,
-
# ASCII value 32) and horizontal tab (HTAB, ASCII value 9) characters
-
# (together known as the white space characters, WSP), and those WSP
-
# characters are subject to header "folding" and "unfolding" as
-
# described in section 2.2.3. Semantic analysis of structured field
-
# bodies is given along with their syntax.
-
1
class StructuredField
-
-
1
include Mail::CommonField
-
1
include Mail::Utilities
-
-
1
def initialize(name = nil, value = nil, charset = nil)
-
14
self.name = name
-
14
self.value = value
-
14
self.charset = charset
-
14
self
-
end
-
-
1
def charset
-
2
@charset
-
end
-
-
1
def charset=(val)
-
28
@charset = val
-
end
-
-
1
def default
-
decoded
-
end
-
-
1
def errors
-
[]
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# subject = "Subject:" unstructured CRLF
-
1
module Mail
-
1
class SubjectField < UnstructuredField
-
-
1
FIELD_NAME = 'subject'
-
1
CAPITALIZED_FIELD = "Subject"
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
2
self.charset = charset
-
2
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
end
-
-
end
-
end
-
# encoding: utf-8
-
#
-
# = To Field
-
#
-
# The To field inherits to StructuredField and handles the To: header
-
# field in the email.
-
#
-
# Sending to to a mail message will instantiate a Mail::Field object that
-
# has a ToField as its field type. This includes all Mail::CommonAddress
-
# module instance metods.
-
#
-
# Only one To field can appear in a header, though it can have multiple
-
# addresses and groups of addresses.
-
#
-
# == Examples:
-
#
-
# mail = Mail.new
-
# mail.to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
-
# mail['to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
-
# mail['To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
-
#
-
# mail[:to].encoded #=> 'To: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
-
# mail[:to].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail[:to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
# mail[:to].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
-
#
-
1
require 'mail/fields/common/common_address'
-
-
1
module Mail
-
1
class ToField < StructuredField
-
-
1
include Mail::CommonAddress
-
-
1
FIELD_NAME = 'to'
-
1
CAPITALIZED_FIELD = 'To'
-
-
1
def initialize(value = nil, charset = 'utf-8')
-
2
self.charset = charset
-
2
super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
-
2
self.parse
-
2
self
-
end
-
-
1
def encoded
-
do_encode(CAPITALIZED_FIELD)
-
end
-
-
1
def decoded
-
do_decode
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
require 'mail/fields/common/common_field'
-
-
1
module Mail
-
# Provides access to an unstructured header field
-
#
-
# ===Per RFC 2822:
-
# 2.2.1. Unstructured Header Field Bodies
-
#
-
# Some field bodies in this standard are defined simply as
-
# "unstructured" (which is specified below as any US-ASCII characters,
-
# except for CR and LF) with no further restrictions. These are
-
# referred to as unstructured field bodies. Semantically, unstructured
-
# field bodies are simply to be treated as a single line of characters
-
# with no further processing (except for header "folding" and
-
# "unfolding" as described in section 2.2.3).
-
1
class UnstructuredField
-
-
1
include Mail::CommonField
-
1
include Mail::Utilities
-
-
1
attr_accessor :charset
-
1
attr_reader :errors
-
-
1
def initialize(name, value, charset = nil)
-
2
@errors = []
-
-
2
if value.is_a?(Array)
-
# Probably has arrived here from a failed parse of an AddressList Field
-
value = value.join(', ')
-
else
-
# Ensure we are dealing with a string
-
2
value = value.to_s
-
end
-
-
2
if charset
-
2
self.charset = charset
-
else
-
if value.respond_to?(:encoding)
-
self.charset = value.encoding
-
else
-
self.charset = $KCODE
-
end
-
end
-
2
self.name = name
-
2
self.value = value
-
2
self
-
end
-
-
1
def encoded
-
do_encode
-
end
-
-
1
def decoded
-
1
do_decode
-
end
-
-
1
def default
-
1
decoded
-
end
-
-
1
def parse # An unstructured field does not parse
-
self
-
end
-
-
1
private
-
-
1
def do_encode
-
value.nil? ? '' : "#{wrapped_value}\r\n"
-
end
-
-
1
def do_decode
-
1
value.blank? ? nil : Encodings.decode_encode(value, :decode)
-
end
-
-
# 2.2.3. Long Header Fields
-
#
-
# Each header field is logically a single line of characters comprising
-
# the field name, the colon, and the field body. For convenience
-
# however, and to deal with the 998/78 character limitations per line,
-
# the field body portion of a header field can be split into a multiple
-
# line representation; this is called "folding". The general rule is
-
# that wherever this standard allows for folding white space (not
-
# simply WSP characters), a CRLF may be inserted before any WSP. For
-
# example, the header field:
-
#
-
# Subject: This is a test
-
#
-
# can be represented as:
-
#
-
# Subject: This
-
# is a test
-
#
-
# Note: Though structured field bodies are defined in such a way that
-
# folding can take place between many of the lexical tokens (and even
-
# within some of the lexical tokens), folding SHOULD be limited to
-
# placing the CRLF at higher-level syntactic breaks. For instance, if
-
# a field body is defined as comma-separated values, it is recommended
-
# that folding occur after the comma separating the structured items in
-
# preference to other places where the field could be folded, even if
-
# it is allowed elsewhere.
-
1
def wrapped_value # :nodoc:
-
wrap_lines(name, fold("#{name}: ".length))
-
end
-
-
# 6.2. Display of 'encoded-word's
-
#
-
# When displaying a particular header field that contains multiple
-
# 'encoded-word's, any 'linear-white-space' that separates a pair of
-
# adjacent 'encoded-word's is ignored. (This is to allow the use of
-
# multiple 'encoded-word's to represent long strings of unencoded text,
-
# without having to separate 'encoded-word's where spaces occur in the
-
# unencoded text.)
-
1
def wrap_lines(name, folded_lines)
-
result = ["#{name}: #{folded_lines.shift}"]
-
result.concat(folded_lines)
-
result.join("\r\n\s")
-
end
-
-
1
def fold(prepend = 0) # :nodoc:
-
encoding = normalized_encoding
-
decoded_string = decoded.to_s
-
should_encode = decoded_string.not_ascii_only?
-
if should_encode
-
first = true
-
words = decoded_string.split(/[ \t]/).map do |word|
-
if first
-
first = !first
-
else
-
word = " " << word
-
end
-
if word.not_ascii_only?
-
word
-
else
-
word.scan(/.{7}|.+$/)
-
end
-
end.flatten
-
else
-
words = decoded_string.split(/[ \t]/)
-
end
-
-
folded_lines = []
-
while !words.empty?
-
limit = 78 - prepend
-
limit = limit - 7 - encoding.length if should_encode
-
line = ""
-
while !words.empty?
-
break unless word = words.first.dup
-
word.encode!(charset) if charset && word.respond_to?(:encode!)
-
word = encode(word) if should_encode
-
word = encode_crlf(word)
-
# Skip to next line if we're going to go past the limit
-
# Unless this is the first word, in which case we're going to add it anyway
-
# Note: This means that a word that's longer than 998 characters is going to break the spec. Please fix if this is a problem for you.
-
# (The fix, it seems, would be to use encoded-word encoding on it, because that way you can break it across multiple lines and
-
# the linebreak will be ignored)
-
break if !line.empty? && (line.length + word.length + 1 > limit)
-
# Remove the word from the queue ...
-
words.shift
-
# Add word separator
-
line << " " unless (line.empty? || should_encode)
-
# ... add it in encoded form to the current line
-
line << word
-
end
-
# Encode the line if necessary
-
line = "=?#{encoding}?Q?#{line}?=" if should_encode
-
# Add the line to the output and reset the prepend
-
folded_lines << line
-
prepend = 0
-
end
-
folded_lines
-
end
-
-
1
def encode(value)
-
value = [value].pack("M").gsub("=\n", '')
-
value.gsub!(/"/, '=22')
-
value.gsub!(/\(/, '=28')
-
value.gsub!(/\)/, '=29')
-
value.gsub!(/\?/, '=3F')
-
value.gsub!(/_/, '=5F')
-
value.gsub!(/ /, '_')
-
value
-
end
-
-
1
def encode_crlf(value)
-
value.gsub!("\r", '=0D')
-
value.gsub!("\n", '=0A')
-
value
-
end
-
-
1
def normalized_encoding
-
encoding = charset.to_s.upcase.gsub('_', '-')
-
encoding = 'UTF-8' if encoding == 'UTF8' # Ruby 1.8.x and $KCODE == 'u'
-
encoding
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
-
# Provides access to a header object.
-
#
-
# ===Per RFC2822
-
#
-
# 2.2. Header Fields
-
#
-
# Header fields are lines composed of a field name, followed by a colon
-
# (":"), followed by a field body, and terminated by CRLF. A field
-
# name MUST be composed of printable US-ASCII characters (i.e.,
-
# characters that have values between 33 and 126, inclusive), except
-
# colon. A field body may be composed of any US-ASCII characters,
-
# except for CR and LF. However, a field body may contain CRLF when
-
# used in header "folding" and "unfolding" as described in section
-
# 2.2.3. All field bodies MUST conform to the syntax described in
-
# sections 3 and 4 of this standard.
-
1
class Header
-
1
include Patterns
-
1
include Utilities
-
1
include Enumerable
-
-
1
@@maximum_amount = 1000
-
-
# Large amount of headers in Email might create extra high CPU load
-
# Use this parameter to limit number of headers that will be parsed by
-
# mail library.
-
# Default: 1000
-
1
def self.maximum_amount
-
@@maximum_amount
-
end
-
-
1
def self.maximum_amount=(value)
-
@@maximum_amount = value
-
end
-
-
# Creates a new header object.
-
#
-
# Accepts raw text or nothing. If given raw text will attempt to parse
-
# it and split it into the various fields, instantiating each field as
-
# it goes.
-
#
-
# If it finds a field that should be a structured field (such as content
-
# type), but it fails to parse it, it will simply make it an unstructured
-
# field and leave it alone. This will mean that the data is preserved but
-
# no automatic processing of that field will happen. If you find one of
-
# these cases, please make a patch and send it in, or at the least, send
-
# me the example so we can fix it.
-
1
def initialize(header_text = nil, charset = nil)
-
4
@errors = []
-
4
@charset = charset
-
4
self.raw_source = header_text.to_crlf.lstrip
-
4
split_header if header_text
-
end
-
-
# The preserved raw source of the header as you passed it in, untouched
-
# for your Regexing glory.
-
1
def raw_source
-
@raw_source
-
end
-
-
# Returns an array of all the fields in the header in order that they
-
# were read in.
-
1
def fields
-
78
@fields ||= FieldList.new
-
end
-
-
# 3.6. Field definitions
-
#
-
# It is important to note that the header fields are not guaranteed to
-
# be in a particular order. They may appear in any order, and they
-
# have been known to be reordered occasionally when transported over
-
# the Internet. However, for the purposes of this standard, header
-
# fields SHOULD NOT be reordered when a message is transported or
-
# transformed. More importantly, the trace header fields and resent
-
# header fields MUST NOT be reordered, and SHOULD be kept in blocks
-
# prepended to the message. See sections 3.6.6 and 3.6.7 for more
-
# information.
-
#
-
# Populates the fields container with Field objects in the order it
-
# receives them in.
-
#
-
# Acceps an array of field string values, for example:
-
#
-
# h = Header.new
-
# h.fields = ['From: mikel@me.com', 'To: bob@you.com']
-
1
def fields=(unfolded_fields)
-
@fields = Mail::FieldList.new
-
warn "Warning: more than #{self.class.maximum_amount} header fields only using the first #{self.class.maximum_amount}" if unfolded_fields.length > self.class.maximum_amount
-
unfolded_fields[0..(self.class.maximum_amount-1)].each do |field|
-
-
field = Field.new(field, nil, charset)
-
field.errors.each { |error| self.errors << error }
-
if limited_field?(field.name) && (selected = select_field_for(field.name)) && selected.any?
-
selected.first.update(field.name, field.value)
-
else
-
@fields << field
-
end
-
end
-
-
end
-
-
1
def errors
-
@errors
-
end
-
-
# 3.6. Field definitions
-
#
-
# The following table indicates limits on the number of times each
-
# field may occur in a message header as well as any special
-
# limitations on the use of those fields. An asterisk next to a value
-
# in the minimum or maximum column indicates that a special restriction
-
# appears in the Notes column.
-
#
-
# <snip table from 3.6>
-
#
-
# As per RFC, many fields can appear more than once, we will return a string
-
# of the value if there is only one header, or if there is more than one
-
# matching header, will return an array of values in order that they appear
-
# in the header ordered from top to bottom.
-
#
-
# Example:
-
#
-
# h = Header.new
-
# h.fields = ['To: mikel@me.com', 'X-Mail-SPAM: 15', 'X-Mail-SPAM: 20']
-
# h['To'] #=> 'mikel@me.com'
-
# h['X-Mail-SPAM'] #=> ['15', '20']
-
1
def [](name)
-
48
name = dasherize(name).downcase
-
48
selected = select_field_for(name)
-
case
-
when selected.length > 1
-
selected.map { |f| f }
-
when !selected.blank?
-
34
selected.first
-
else
-
nil
-
48
end
-
end
-
-
# Sets the FIRST matching field in the header to passed value, or deletes
-
# the FIRST field matched from the header if passed nil
-
#
-
# Example:
-
#
-
# h = Header.new
-
# h.fields = ['To: mikel@me.com', 'X-Mail-SPAM: 15', 'X-Mail-SPAM: 20']
-
# h['To'] = 'bob@you.com'
-
# h['To'] #=> 'bob@you.com'
-
# h['X-Mail-SPAM'] = '10000'
-
# h['X-Mail-SPAM'] # => ['15', '20', '10000']
-
# h['X-Mail-SPAM'] = nil
-
# h['X-Mail-SPAM'] # => nil
-
1
def []=(name, value)
-
16
name = dasherize(name)
-
16
if name.include?(':')
-
raise ArgumentError, "Header names may not contain a colon: #{name.inspect}"
-
end
-
16
fn = name.downcase
-
16
selected = select_field_for(fn)
-
-
case
-
# User wants to delete the field
-
when !selected.blank? && value == nil
-
fields.delete_if { |f| selected.include?(f) }
-
-
# User wants to change the field
-
when !selected.blank? && limited_field?(fn)
-
2
selected.first.update(fn, value)
-
-
# User wants to create the field
-
else
-
# Need to insert in correct order for trace fields
-
14
self.fields << Field.new(name.to_s, value, charset)
-
16
end
-
16
if dasherize(fn) == "content-type"
-
# Update charset if specified in Content-Type
-
6
params = self[:content_type].parameters rescue nil
-
6
@charset = params && params[:charset]
-
end
-
end
-
-
1
def charset
-
14
@charset
-
end
-
-
1
def charset=(val)
-
6
params = self[:content_type].parameters rescue nil
-
6
if params
-
2
params[:charset] = val
-
end
-
6
@charset = val
-
end
-
-
1
LIMITED_FIELDS = %w[ date from sender reply-to to cc bcc
-
message-id in-reply-to references subject
-
return-path content-type mime-version
-
content-transfer-encoding content-description
-
content-id content-disposition content-location]
-
-
1
def encoded
-
buffer = ''
-
buffer.force_encoding('us-ascii') if buffer.respond_to?(:force_encoding)
-
fields.each do |field|
-
buffer << field.encoded
-
end
-
buffer
-
end
-
-
1
def to_s
-
encoded
-
end
-
-
1
def decoded
-
raise NoMethodError, 'Can not decode an entire header as there could be character set conflicts, try calling #decoded on the various fields.'
-
end
-
-
1
def field_summary
-
fields.map { |f| "<#{f.name}: #{f.value}>" }.join(", ")
-
end
-
-
# Returns true if the header has a Message-ID defined (empty or not)
-
1
def has_message_id?
-
!fields.select { |f| f.responsible_for?('Message-ID') }.empty?
-
end
-
-
# Returns true if the header has a Content-ID defined (empty or not)
-
1
def has_content_id?
-
!fields.select { |f| f.responsible_for?('Content-ID') }.empty?
-
end
-
-
# Returns true if the header has a Date defined (empty or not)
-
1
def has_date?
-
!fields.select { |f| f.responsible_for?('Date') }.empty?
-
end
-
-
# Returns true if the header has a MIME version defined (empty or not)
-
1
def has_mime_version?
-
!fields.select { |f| f.responsible_for?('Mime-Version') }.empty?
-
end
-
-
1
private
-
-
1
def raw_source=(val)
-
4
@raw_source = val
-
end
-
-
# 2.2.3. Long Header Fields
-
#
-
# The process of moving from this folded multiple-line representation
-
# of a header field to its single line representation is called
-
# "unfolding". Unfolding is accomplished by simply removing any CRLF
-
# that is immediately followed by WSP. Each header field should be
-
# treated in its unfolded form for further syntactic and semantic
-
# evaluation.
-
1
def unfold(string)
-
string.gsub(/#{CRLF}#{WSP}+/, ' ').gsub(/#{WSP}+/, ' ')
-
end
-
-
# Returns the header with all the folds removed
-
1
def unfolded_header
-
@unfolded_header ||= unfold(raw_source)
-
end
-
-
# Splits an unfolded and line break cleaned header into individual field
-
# strings.
-
1
def split_header
-
self.fields = unfolded_header.split(CRLF)
-
end
-
-
1
def select_field_for(name)
-
270
fields.select { |f| f.responsible_for?(name) }
-
end
-
-
1
def limited_field?(name)
-
2
LIMITED_FIELDS.include?(name.to_s.downcase)
-
end
-
-
# Enumerable support; yield each field in order to the block if there is one,
-
# or return an Enumerator for them if there isn't.
-
1
def each( &block )
-
return self.fields.each( &block ) if block
-
self.fields.each
-
end
-
-
end
-
end
-
# encoding: utf-8
-
-
# This is an almost cut and paste from ActiveSupport v3.0.6, copied in here so that Mail
-
# itself does not depend on ActiveSupport to avoid versioning conflicts
-
-
1
module Mail
-
1
class IndifferentHash < Hash
-
-
1
def initialize(constructor = {})
-
6
if constructor.is_a?(Hash)
-
6
super()
-
6
update(constructor)
-
else
-
super(constructor)
-
end
-
end
-
-
1
def default(key = nil)
-
4
if key.is_a?(Symbol) && include?(key = key.to_s)
-
self[key]
-
else
-
4
super
-
end
-
end
-
-
1
def self.new_from_hash_copying_default(hash)
-
IndifferentHash.new(hash).tap do |new_hash|
-
new_hash.default = hash.default
-
end
-
end
-
-
1
alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
-
1
alias_method :regular_update, :update unless method_defined?(:regular_update)
-
-
# Assigns a new value to the hash:
-
#
-
# hash = HashWithIndifferentAccess.new
-
# hash[:key] = "value"
-
#
-
1
def []=(key, value)
-
2
regular_writer(convert_key(key), convert_value(value))
-
end
-
-
1
alias_method :store, :[]=
-
-
# Updates the instantized hash with values from the second:
-
#
-
# hash_1 = HashWithIndifferentAccess.new
-
# hash_1[:key] = "value"
-
#
-
# hash_2 = HashWithIndifferentAccess.new
-
# hash_2[:key] = "New Value!"
-
#
-
# hash_1.update(hash_2) # => {"key"=>"New Value!"}
-
#
-
1
def update(other_hash)
-
10
other_hash.each_pair { |key, value| regular_writer(convert_key(key), convert_value(value)) }
-
8
self
-
end
-
-
1
alias_method :merge!, :update
-
-
# Checks the hash for a key matching the argument passed in:
-
#
-
# hash = HashWithIndifferentAccess.new
-
# hash["key"] = "value"
-
# hash.key? :key # => true
-
# hash.key? "key" # => true
-
#
-
1
def key?(key)
-
4
super(convert_key(key))
-
end
-
-
1
alias_method :include?, :key?
-
1
alias_method :has_key?, :key?
-
1
alias_method :member?, :key?
-
-
# Fetches the value for the specified key, same as doing hash[key]
-
1
def fetch(key, *extras)
-
super(convert_key(key), *extras)
-
end
-
-
# Returns an array of the values at the specified indices:
-
#
-
# hash = HashWithIndifferentAccess.new
-
# hash[:a] = "x"
-
# hash[:b] = "y"
-
# hash.values_at("a", "b") # => ["x", "y"]
-
#
-
1
def values_at(*indices)
-
indices.collect {|key| self[convert_key(key)]}
-
end
-
-
# Returns an exact copy of the hash.
-
1
def dup
-
IndifferentHash.new(self)
-
end
-
-
# Merges the instantized and the specified hashes together, giving precedence to the values from the second hash
-
# Does not overwrite the existing hash.
-
1
def merge(hash)
-
self.dup.update(hash)
-
end
-
-
# Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
-
# This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
-
1
def reverse_merge(other_hash)
-
super self.class.new_from_hash_copying_default(other_hash)
-
end
-
-
1
def reverse_merge!(other_hash)
-
replace(reverse_merge( other_hash ))
-
end
-
-
# Removes a specified key from the hash.
-
1
def delete(key)
-
super(convert_key(key))
-
end
-
-
1
def stringify_keys!; self end
-
1
def stringify_keys; dup end
-
1
def symbolize_keys; to_hash.symbolize_keys end
-
1
def to_options!; self end
-
-
1
def to_hash
-
Hash.new(default).merge!(self)
-
end
-
-
1
protected
-
-
1
def convert_key(key)
-
8
key.kind_of?(Symbol) ? key.to_s : key
-
end
-
-
1
def convert_value(value)
-
4
if value.class == Hash
-
self.class.new_from_hash_copying_default(value)
-
4
elsif value.is_a?(Array)
-
value.dup.replace(value.map { |e| convert_value(e) })
-
else
-
4
value
-
end
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
-
# Allows you to create a new Mail::Message object.
-
#
-
# You can make an email via passing a string or passing a block.
-
#
-
# For example, the following two examples will create the same email
-
# message:
-
#
-
# Creating via a string:
-
#
-
# string = "To: mikel@test.lindsaar.net\r\n"
-
# string << "From: bob@test.lindsaar.net\r\n"
-
# string << "Subject: This is an email\r\n"
-
# string << "\r\n"
-
# string << "This is the body"
-
# Mail.new(string)
-
#
-
# Or creating via a block:
-
#
-
# message = Mail.new do
-
# to 'mikel@test.lindsaar.net'
-
# from 'bob@test.lindsaar.net'
-
# subject 'This is an email'
-
# body 'This is the body'
-
# end
-
#
-
# Or creating via a hash (or hash like object):
-
#
-
# message = Mail.new({:to => 'mikel@test.lindsaar.net',
-
# 'from' => 'bob@test.lindsaar.net',
-
# :subject => 'This is an email',
-
# :body => 'This is the body' })
-
#
-
# Note, the hash keys can be strings or symbols, the passed in object
-
# does not need to be a hash, it just needs to respond to :each_pair
-
# and yield each key value pair.
-
#
-
# As a side note, you can also create a new email through creating
-
# a Mail::Message object directly and then passing in values via string,
-
# symbol or direct method calls. See Mail::Message for more information.
-
#
-
# mail = Mail.new
-
# mail.to = 'mikel@test.lindsaar.net'
-
# mail[:from] = 'bob@test.lindsaar.net'
-
# mail['subject'] = 'This is an email'
-
# mail.body = 'This is the body'
-
1
def self.new(*args, &block)
-
4
Message.new(args, &block)
-
end
-
-
# Sets the default delivery method and retriever method for all new Mail objects.
-
# The delivery_method and retriever_method default to :smtp and :pop3, with defaults
-
# set.
-
#
-
# So sending a new email, if you have an SMTP server running on localhost is
-
# as easy as:
-
#
-
# Mail.deliver do
-
# to 'mikel@test.lindsaar.net'
-
# from 'bob@test.lindsaar.net'
-
# subject 'hi there!'
-
# body 'this is a body'
-
# end
-
#
-
# If you do not specify anything, you will get the following equivalent code set in
-
# every new mail object:
-
#
-
# Mail.defaults do
-
# delivery_method :smtp, { :address => "localhost",
-
# :port => 25,
-
# :domain => 'localhost.localdomain',
-
# :user_name => nil,
-
# :password => nil,
-
# :authentication => nil,
-
# :enable_starttls_auto => true }
-
#
-
# retriever_method :pop3, { :address => "localhost",
-
# :port => 995,
-
# :user_name => nil,
-
# :password => nil,
-
# :enable_ssl => true }
-
# end
-
#
-
# Mail.delivery_method.new #=> Mail::SMTP instance
-
# Mail.retriever_method.new #=> Mail::POP3 instance
-
#
-
# Each mail object inherits the default set in Mail.delivery_method, however, on
-
# a per email basis, you can override the method:
-
#
-
# mail.delivery_method :sendmail
-
#
-
# Or you can override the method and pass in settings:
-
#
-
# mail.delivery_method :sendmail, { :address => 'some.host' }
-
#
-
# You can also just modify the settings:
-
#
-
# mail.delivery_settings = { :address => 'some.host' }
-
#
-
# The passed in hash is just merged against the defaults with +merge!+ and the result
-
# assigned the mail object. So the above example will change only the :address value
-
# of the global smtp_settings to be 'some.host', keeping all other values
-
1
def self.defaults(&block)
-
Configuration.instance.instance_eval(&block)
-
end
-
-
# Returns the delivery method selected, defaults to an instance of Mail::SMTP
-
1
def self.delivery_method
-
4
Configuration.instance.delivery_method
-
end
-
-
# Returns the retriever method selected, defaults to an instance of Mail::POP3
-
1
def self.retriever_method
-
Configuration.instance.retriever_method
-
end
-
-
# Send an email using the default configuration. You do need to set a default
-
# configuration first before you use self.deliver, if you don't, an appropriate
-
# error will be raised telling you to.
-
#
-
# If you do not specify a delivery type, SMTP will be used.
-
#
-
# Mail.deliver do
-
# to 'mikel@test.lindsaar.net'
-
# from 'ada@test.lindsaar.net'
-
# subject 'This is a test email'
-
# body 'Not much to say here'
-
# end
-
#
-
# You can also do:
-
#
-
# mail = Mail.read('email.eml')
-
# mail.deliver!
-
#
-
# And your email object will be created and sent.
-
1
def self.deliver(*args, &block)
-
mail = self.new(args, &block)
-
mail.deliver
-
mail
-
end
-
-
# Find emails from the default retriever
-
# See Mail::Retriever for a complete documentation.
-
1
def self.find(*args, &block)
-
retriever_method.find(*args, &block)
-
end
-
-
# Finds and then deletes retrieved emails from the default retriever
-
# See Mail::Retriever for a complete documentation.
-
1
def self.find_and_delete(*args, &block)
-
retriever_method.find_and_delete(*args, &block)
-
end
-
-
# Receive the first email(s) from the default retriever
-
# See Mail::Retriever for a complete documentation.
-
1
def self.first(*args, &block)
-
retriever_method.first(*args, &block)
-
end
-
-
# Receive the first email(s) from the default retriever
-
# See Mail::Retriever for a complete documentation.
-
1
def self.last(*args, &block)
-
retriever_method.last(*args, &block)
-
end
-
-
# Receive all emails from the default retriever
-
# See Mail::Retriever for a complete documentation.
-
1
def self.all(*args, &block)
-
retriever_method.all(*args, &block)
-
end
-
-
# Reads in an email message from a path and instantiates it as a new Mail::Message
-
1
def self.read(filename)
-
self.new(File.open(filename, 'rb') { |f| f.read })
-
end
-
-
# Delete all emails from the default retriever
-
# See Mail::Retriever for a complete documentation.
-
1
def self.delete_all(*args, &block)
-
retriever_method.delete_all(*args, &block)
-
end
-
-
# Instantiates a new Mail::Message using a string
-
1
def Mail.read_from_string(mail_as_string)
-
Mail.new(mail_as_string)
-
end
-
-
1
def Mail.connection(&block)
-
retriever_method.connection(&block)
-
end
-
-
# Initialize the observers and interceptors arrays
-
1
@@delivery_notification_observers = []
-
1
@@delivery_interceptors = []
-
-
# You can register an object to be informed of every email that is sent through
-
# this method.
-
#
-
# Your object needs to respond to a single method #delivered_email(mail)
-
# which receives the email that is sent.
-
1
def self.register_observer(observer)
-
unless @@delivery_notification_observers.include?(observer)
-
@@delivery_notification_observers << observer
-
end
-
end
-
-
# You can register an object to be given every mail object that will be sent,
-
# before it is sent. So if you want to add special headers or modify any
-
# email that gets sent through the Mail library, you can do so.
-
#
-
# Your object needs to respond to a single method #delivering_email(mail)
-
# which receives the email that is about to be sent. Make your modifications
-
# directly to this object.
-
1
def self.register_interceptor(interceptor)
-
unless @@delivery_interceptors.include?(interceptor)
-
@@delivery_interceptors << interceptor
-
end
-
end
-
-
1
def self.inform_observers(mail)
-
@@delivery_notification_observers.each do |observer|
-
observer.delivered_email(mail)
-
end
-
end
-
-
1
def self.inform_interceptors(mail)
-
@@delivery_interceptors.each do |interceptor|
-
interceptor.delivering_email(mail)
-
end
-
end
-
-
1
protected
-
-
1
def self.random_tag
-
t = Time.now
-
sprintf('%x%x_%x%x%d%x',
-
t.to_i, t.tv_usec,
-
$$, Thread.current.object_id.abs, self.uniq, rand(255))
-
end
-
-
1
private
-
-
1
def self.something_random
-
1
(Thread.current.object_id * rand(255) / Time.now.to_f).to_s.slice(-3..-1).to_i
-
end
-
-
1
def self.uniq
-
@@uniq += 1
-
end
-
-
1
@@uniq = self.something_random
-
-
end
-
1
module Mail
-
1
module Matchers
-
1
def have_sent_email
-
HasSentEmailMatcher.new(self)
-
end
-
-
1
class HasSentEmailMatcher
-
1
def initialize(_context)
-
end
-
-
1
def matches?(subject)
-
matching_deliveries = filter_matched_deliveries(Mail::TestMailer.deliveries)
-
!(matching_deliveries.empty?)
-
end
-
-
1
def from(sender)
-
@sender = sender
-
self
-
end
-
-
1
def to(recipient_or_list)
-
@recipients ||= []
-
-
if recipient_or_list.kind_of?(Array)
-
@recipients += recipient_or_list
-
else
-
@recipients << recipient_or_list
-
end
-
self
-
end
-
-
1
def with_subject(subject)
-
@subject = subject
-
self
-
end
-
-
1
def matching_subject(subject_matcher)
-
@subject_matcher = subject_matcher
-
self
-
end
-
-
1
def with_body(body)
-
@body = body
-
self
-
end
-
-
1
def matching_body(body_matcher)
-
@body_matcher = body_matcher
-
self
-
end
-
-
1
def description
-
result = "send a matching email"
-
result
-
end
-
-
1
def failure_message
-
result = "Expected email to be sent "
-
result += explain_expectations
-
result += dump_deliveries
-
result
-
end
-
-
1
def negative_failure_message
-
result = "Expected no email to be sent "
-
result += explain_expectations
-
result += dump_deliveries
-
result
-
end
-
-
1
protected
-
-
1
def filter_matched_deliveries(deliveries)
-
candidate_deliveries = deliveries
-
-
%w(sender recipients subject subject_matcher body body_matcher).each do |modifier_name|
-
next unless instance_variable_defined?("@#{modifier_name}")
-
candidate_deliveries = candidate_deliveries.select{|matching_delivery| self.send("matches_on_#{modifier_name}?", matching_delivery)}
-
end
-
-
candidate_deliveries
-
end
-
-
1
def matches_on_sender?(delivery)
-
delivery.from.include?(@sender)
-
end
-
-
1
def matches_on_recipients?(delivery)
-
@recipients.all? {|recipient| delivery.to.include?(recipient) }
-
end
-
-
1
def matches_on_subject?(delivery)
-
delivery.subject == @subject
-
end
-
-
1
def matches_on_subject_matcher?(delivery)
-
@subject_matcher.match delivery.subject
-
end
-
-
1
def matches_on_body?(delivery)
-
delivery.body == @body
-
end
-
-
1
def matches_on_body_matcher?(delivery)
-
@body_matcher.match delivery.body.raw_source
-
end
-
-
1
def explain_expectations
-
result = ''
-
result += "from #{@sender} " if instance_variable_defined?('@sender')
-
result += "to #{@recipients.inspect} " if instance_variable_defined?('@recipients')
-
result += "with subject \"#{@subject}\" " if instance_variable_defined?('@subject')
-
result += "with subject matching \"#{@subject_matcher}\" " if instance_variable_defined?('@subject_matcher')
-
result += "with body \"#{@body}\" " if instance_variable_defined?('@body')
-
result += "with body matching \"#{@body_matcher}\" " if instance_variable_defined?('@body_matcher')
-
result
-
end
-
-
1
def dump_deliveries
-
"(actual deliveries: " + Mail::TestMailer.deliveries.inspect + ")"
-
end
-
end
-
end
-
end
-
# encoding: utf-8
-
1
require "yaml"
-
-
1
module Mail
-
# The Message class provides a single point of access to all things to do with an
-
# email message.
-
#
-
# You create a new email message by calling the Mail::Message.new method, or just
-
# Mail.new
-
#
-
# A Message object by default has the following objects inside it:
-
#
-
# * A Header object which contains all information and settings of the header of the email
-
# * Body object which contains all parts of the email that are not part of the header, this
-
# includes any attachments, body text, MIME parts etc.
-
#
-
# ==Per RFC2822
-
#
-
# 2.1. General Description
-
#
-
# At the most basic level, a message is a series of characters. A
-
# message that is conformant with this standard is comprised of
-
# characters with values in the range 1 through 127 and interpreted as
-
# US-ASCII characters [ASCII]. For brevity, this document sometimes
-
# refers to this range of characters as simply "US-ASCII characters".
-
#
-
# Note: This standard specifies that messages are made up of characters
-
# in the US-ASCII range of 1 through 127. There are other documents,
-
# specifically the MIME document series [RFC2045, RFC2046, RFC2047,
-
# RFC2048, RFC2049], that extend this standard to allow for values
-
# outside of that range. Discussion of those mechanisms is not within
-
# the scope of this standard.
-
#
-
# Messages are divided into lines of characters. A line is a series of
-
# characters that is delimited with the two characters carriage-return
-
# and line-feed; that is, the carriage return (CR) character (ASCII
-
# value 13) followed immediately by the line feed (LF) character (ASCII
-
# value 10). (The carriage-return/line-feed pair is usually written in
-
# this document as "CRLF".)
-
#
-
# A message consists of header fields (collectively called "the header
-
# of the message") followed, optionally, by a body. The header is a
-
# sequence of lines of characters with special syntax as defined in
-
# this standard. The body is simply a sequence of characters that
-
# follows the header and is separated from the header by an empty line
-
# (i.e., a line with nothing preceding the CRLF).
-
1
class Message
-
-
1
include Patterns
-
1
include Utilities
-
-
# ==Making an email
-
#
-
# You can make an new mail object via a block, passing a string, file or direct assignment.
-
#
-
# ===Making an email via a block
-
#
-
# mail = Mail.new do
-
# from 'mikel@test.lindsaar.net'
-
# to 'you@test.lindsaar.net'
-
# subject 'This is a test email'
-
# body File.read('body.txt')
-
# end
-
#
-
# mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
-
#
-
# ===Making an email via passing a string
-
#
-
# mail = Mail.new("To: mikel@test.lindsaar.net\r\nSubject: Hello\r\n\r\nHi there!")
-
# mail.body.to_s #=> 'Hi there!'
-
# mail.subject #=> 'Hello'
-
# mail.to #=> 'mikel@test.lindsaar.net'
-
#
-
# ===Making an email from a file
-
#
-
# mail = Mail.read('path/to/file.eml')
-
# mail.body.to_s #=> 'Hi there!'
-
# mail.subject #=> 'Hello'
-
# mail.to #=> 'mikel@test.lindsaar.net'
-
#
-
# ===Making an email via assignment
-
#
-
# You can assign values to a mail object via four approaches:
-
#
-
# * Message#field_name=(value)
-
# * Message#field_name(value)
-
# * Message#['field_name']=(value)
-
# * Message#[:field_name]=(value)
-
#
-
# Examples:
-
#
-
# mail = Mail.new
-
# mail['from'] = 'mikel@test.lindsaar.net'
-
# mail[:to] = 'you@test.lindsaar.net'
-
# mail.subject 'This is a test email'
-
# mail.body = 'This is a body'
-
#
-
# mail.to_s #=> "From: mikel@test.lindsaar.net\r\nTo: you@...
-
#
-
1
def initialize(*args, &block)
-
4
@body = nil
-
4
@body_raw = nil
-
4
@separate_parts = false
-
4
@text_part = nil
-
4
@html_part = nil
-
4
@errors = nil
-
4
@header = nil
-
4
@charset = 'UTF-8'
-
4
@defaulted_charset = true
-
-
4
@smtp_envelope_from = nil
-
4
@smtp_envelope_to = nil
-
-
4
@perform_deliveries = true
-
4
@raise_delivery_errors = true
-
-
4
@delivery_handler = nil
-
-
4
@delivery_method = Mail.delivery_method.dup
-
-
4
@transport_encoding = Mail::Encodings.get_encoding('7bit')
-
-
4
@mark_for_delete = false
-
-
4
if args.flatten.first.respond_to?(:each_pair)
-
init_with_hash(args.flatten.first)
-
else
-
4
init_with_string(args.flatten[0].to_s)
-
end
-
-
4
if block_given?
-
instance_eval(&block)
-
end
-
-
4
self
-
end
-
-
# If you assign a delivery handler, mail will call :deliver_mail on the
-
# object you assign to delivery_handler, it will pass itself as the
-
# single argument.
-
#
-
# If you define a delivery_handler, then you are responsible for the
-
# following actions in the delivery cycle:
-
#
-
# * Appending the mail object to Mail.deliveries as you see fit.
-
# * Checking the mail.perform_deliveries flag to decide if you should
-
# actually call :deliver! the mail object or not.
-
# * Checking the mail.raise_delivery_errors flag to decide if you
-
# should raise delivery errors if they occur.
-
# * Actually calling :deliver! (with the bang) on the mail object to
-
# get it to deliver itself.
-
#
-
# A simplest implementation of a delivery_handler would be
-
#
-
# class MyObject
-
#
-
# def initialize
-
# @mail = Mail.new('To: mikel@test.lindsaar.net')
-
# @mail.delivery_handler = self
-
# end
-
#
-
# attr_accessor :mail
-
#
-
# def deliver_mail(mail)
-
# yield
-
# end
-
# end
-
#
-
# Then doing:
-
#
-
# obj = MyObject.new
-
# obj.mail.deliver
-
#
-
# Would cause Mail to call obj.deliver_mail passing itself as a parameter,
-
# which then can just yield and let Mail do its own private do_delivery
-
# method.
-
1
attr_accessor :delivery_handler
-
-
# If set to false, mail will go through the motions of doing a delivery,
-
# but not actually call the delivery method or append the mail object to
-
# the Mail.deliveries collection. Useful for testing.
-
#
-
# Mail.deliveries.size #=> 0
-
# mail.delivery_method :smtp
-
# mail.perform_deliveries = false
-
# mail.deliver # Mail::SMTP not called here
-
# Mail.deliveries.size #=> 0
-
#
-
# If you want to test and query the Mail.deliveries collection to see what
-
# mail you sent, you should set perform_deliveries to true and use
-
# the :test mail delivery_method:
-
#
-
# Mail.deliveries.size #=> 0
-
# mail.delivery_method :test
-
# mail.perform_deliveries = true
-
# mail.deliver
-
# Mail.deliveries.size #=> 1
-
#
-
# This setting is ignored by mail (though still available as a flag) if you
-
# define a delivery_handler
-
1
attr_accessor :perform_deliveries
-
-
# If set to false, mail will silently catch and ignore any exceptions
-
# raised through attempting to deliver an email.
-
#
-
# This setting is ignored by mail (though still available as a flag) if you
-
# define a delivery_handler
-
1
attr_accessor :raise_delivery_errors
-
-
1
def register_for_delivery_notification(observer)
-
STDERR.puts("Message#register_for_delivery_notification is deprecated, please call Mail.register_observer instead")
-
Mail.register_observer(observer)
-
end
-
-
1
def inform_observers
-
Mail.inform_observers(self)
-
end
-
-
1
def inform_interceptors
-
Mail.inform_interceptors(self)
-
end
-
-
# Delivers an mail object.
-
#
-
# Examples:
-
#
-
# mail = Mail.read('file.eml')
-
# mail.deliver
-
1
def deliver
-
inform_interceptors
-
if delivery_handler
-
delivery_handler.deliver_mail(self) { do_delivery }
-
else
-
do_delivery
-
end
-
inform_observers
-
self
-
end
-
-
# This method bypasses checking perform_deliveries and raise_delivery_errors,
-
# so use with caution.
-
#
-
# It still however fires off the intercepters and calls the observers callbacks if they are defined.
-
#
-
# Returns self
-
1
def deliver!
-
inform_interceptors
-
response = delivery_method.deliver!(self)
-
inform_observers
-
delivery_method.settings[:return_response] ? response : self
-
end
-
-
1
def delivery_method(method = nil, settings = {})
-
2
unless method
-
@delivery_method
-
else
-
2
@delivery_method = Configuration.instance.lookup_delivery_method(method).new(settings)
-
end
-
end
-
-
1
def reply(*args, &block)
-
self.class.new.tap do |reply|
-
if message_id
-
bracketed_message_id = "<#{message_id}>"
-
reply.in_reply_to = bracketed_message_id
-
if !references.nil?
-
refs = [references].flatten.map { |r| "<#{r}>" }
-
refs << bracketed_message_id
-
reply.references = refs.join(' ')
-
elsif !in_reply_to.nil? && !in_reply_to.kind_of?(Array)
-
reply.references = "<#{in_reply_to}> #{bracketed_message_id}"
-
end
-
reply.references ||= bracketed_message_id
-
end
-
if subject
-
reply.subject = subject =~ /^Re:/i ? subject : "RE: #{subject}"
-
end
-
if reply_to || from
-
reply.to = self[reply_to ? :reply_to : :from].to_s
-
end
-
if to
-
reply.from = self[:to].formatted.first.to_s
-
end
-
-
unless args.empty?
-
if args.flatten.first.respond_to?(:each_pair)
-
reply.send(:init_with_hash, args.flatten.first)
-
else
-
reply.send(:init_with_string, args.flatten[0].to_s.strip)
-
end
-
end
-
-
if block_given?
-
reply.instance_eval(&block)
-
end
-
end
-
end
-
-
# Provides the operator needed for sort et al.
-
#
-
# Compares this mail object with another mail object, this is done by date, so an
-
# email that is older than another will appear first.
-
#
-
# Example:
-
#
-
# mail1 = Mail.new do
-
# date(Time.now)
-
# end
-
# mail2 = Mail.new do
-
# date(Time.now - 86400) # 1 day older
-
# end
-
# [mail2, mail1].sort #=> [mail2, mail1]
-
1
def <=>(other)
-
if other.nil?
-
1
-
else
-
self.date <=> other.date
-
end
-
end
-
-
# Two emails are the same if they have the same fields and body contents. One
-
# gotcha here is that Mail will insert Message-IDs when calling encoded, so doing
-
# mail1.encoded == mail2.encoded is most probably not going to return what you think
-
# as the assigned Message-IDs by Mail (if not already defined as the same) will ensure
-
# that the two objects are unique, and this comparison will ALWAYS return false.
-
#
-
# So the == operator has been defined like so: Two messages are the same if they have
-
# the same content, ignoring the Message-ID field, unless BOTH emails have a defined and
-
# different Message-ID value, then they are false.
-
#
-
# So, in practice the == operator works like this:
-
#
-
# m1 = Mail.new("Subject: Hello\r\n\r\nHello")
-
# m2 = Mail.new("Subject: Hello\r\n\r\nHello")
-
# m1 == m2 #=> true
-
#
-
# m1 = Mail.new("Subject: Hello\r\n\r\nHello")
-
# m2 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
-
# m1 == m2 #=> true
-
#
-
# m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
-
# m2 = Mail.new("Subject: Hello\r\n\r\nHello")
-
# m1 == m2 #=> true
-
#
-
# m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
-
# m2 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
-
# m1 == m2 #=> true
-
#
-
# m1 = Mail.new("Message-ID: <1234@test>\r\nSubject: Hello\r\n\r\nHello")
-
# m2 = Mail.new("Message-ID: <DIFFERENT@test>\r\nSubject: Hello\r\n\r\nHello")
-
# m1 == m2 #=> false
-
1
def ==(other)
-
return false unless other.respond_to?(:encoded)
-
-
if self.message_id && other.message_id
-
result = (self.encoded == other.encoded)
-
else
-
self_message_id, other_message_id = self.message_id, other.message_id
-
self.message_id, other.message_id = '<temp@test>', '<temp@test>'
-
result = self.encoded == other.encoded
-
self.message_id = "<#{self_message_id}>" if self_message_id
-
other.message_id = "<#{other_message_id}>" if other_message_id
-
result
-
end
-
end
-
-
# Provides access to the raw source of the message as it was when it
-
# was instantiated. This is set at initialization and so is untouched
-
# by the parsers or decoder / encoders
-
#
-
# Example:
-
#
-
# mail = Mail.new('This is an invalid email message')
-
# mail.raw_source #=> "This is an invalid email message"
-
1
def raw_source
-
12
@raw_source
-
end
-
-
# Sets the envelope from for the email
-
1
def set_envelope( val )
-
@raw_envelope = val
-
@envelope = Mail::Envelope.new( val )
-
end
-
-
# The raw_envelope is the From mikel@test.lindsaar.net Mon May 2 16:07:05 2009
-
# type field that you can see at the top of any email that has come
-
# from a mailbox
-
1
def raw_envelope
-
@raw_envelope
-
end
-
-
1
def envelope_from
-
@envelope ? @envelope.from : nil
-
end
-
-
1
def envelope_date
-
@envelope ? @envelope.date : nil
-
end
-
-
# Sets the header of the message object.
-
#
-
# Example:
-
#
-
# mail.header = 'To: mikel@test.lindsaar.net\r\nFrom: Bob@bob.com'
-
# mail.header #=> <#Mail::Header
-
1
def header=(value)
-
4
@header = Mail::Header.new(value, charset)
-
end
-
-
# Returns the header object of the message object. Or, if passed
-
# a parameter sets the value.
-
#
-
# Example:
-
#
-
# mail = Mail::Message.new('To: mikel\r\nFrom: you')
-
# mail.header #=> #<Mail::Header:0x13ce14 @raw_source="To: mikel\r\nFr...
-
#
-
# mail.header #=> nil
-
# mail.header 'To: mikel\r\nFrom: you'
-
# mail.header #=> #<Mail::Header:0x13ce14 @raw_source="To: mikel\r\nFr...
-
1
def header(value = nil)
-
52
value ? self.header = value : @header
-
end
-
-
# Provides a way to set custom headers, by passing in a hash
-
1
def headers(hash = {})
-
hash.each_pair do |k,v|
-
header[k] = v
-
end
-
end
-
-
# Returns a list of parser errors on the header, each field that had an error
-
# will be reparsed as an unstructured field to preserve the data inside, but
-
# will not be used for further processing.
-
#
-
# It returns a nested array of [field_name, value, original_error_message]
-
# per error found.
-
#
-
# Example:
-
#
-
# message = Mail.new("Content-Transfer-Encoding: weirdo\r\n")
-
# message.errors.size #=> 1
-
# message.errors.first[0] #=> "Content-Transfer-Encoding"
-
# message.errors.first[1] #=> "weirdo"
-
# message.errors.first[3] #=> <The original error message exception>
-
#
-
# This is a good first defence on detecting spam by the way. Some spammers send
-
# invalid emails to try and get email parsers to give up parsing them.
-
1
def errors
-
header.errors
-
end
-
-
# Returns the Bcc value of the mail object as an array of strings of
-
# address specs.
-
#
-
# Example:
-
#
-
# mail.bcc = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.bcc #=> ['mikel@test.lindsaar.net']
-
# mail.bcc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.bcc 'Mikel <mikel@test.lindsaar.net>'
-
# mail.bcc #=> ['mikel@test.lindsaar.net']
-
#
-
# Additionally, you can append new addresses to the returned Array like
-
# object.
-
#
-
# Example:
-
#
-
# mail.bcc 'Mikel <mikel@test.lindsaar.net>'
-
# mail.bcc << 'ada@test.lindsaar.net'
-
# mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def bcc( val = nil )
-
default :bcc, val
-
end
-
-
# Sets the Bcc value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.bcc = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.bcc #=> ['mikel@test.lindsaar.net']
-
# mail.bcc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def bcc=( val )
-
header[:bcc] = val
-
end
-
-
# Returns the Cc value of the mail object as an array of strings of
-
# address specs.
-
#
-
# Example:
-
#
-
# mail.cc = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.cc #=> ['mikel@test.lindsaar.net']
-
# mail.cc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.cc 'Mikel <mikel@test.lindsaar.net>'
-
# mail.cc #=> ['mikel@test.lindsaar.net']
-
#
-
# Additionally, you can append new addresses to the returned Array like
-
# object.
-
#
-
# Example:
-
#
-
# mail.cc 'Mikel <mikel@test.lindsaar.net>'
-
# mail.cc << 'ada@test.lindsaar.net'
-
# mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def cc( val = nil )
-
default :cc, val
-
end
-
-
# Sets the Cc value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.cc = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.cc #=> ['mikel@test.lindsaar.net']
-
# mail.cc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def cc=( val )
-
header[:cc] = val
-
end
-
-
1
def comments( val = nil )
-
default :comments, val
-
end
-
-
1
def comments=( val )
-
header[:comments] = val
-
end
-
-
1
def content_description( val = nil )
-
default :content_description, val
-
end
-
-
1
def content_description=( val )
-
header[:content_description] = val
-
end
-
-
1
def content_disposition( val = nil )
-
default :content_disposition, val
-
end
-
-
1
def content_disposition=( val )
-
header[:content_disposition] = val
-
end
-
-
1
def content_id( val = nil )
-
default :content_id, val
-
end
-
-
1
def content_id=( val )
-
header[:content_id] = val
-
end
-
-
1
def content_location( val = nil )
-
default :content_location, val
-
end
-
-
1
def content_location=( val )
-
header[:content_location] = val
-
end
-
-
1
def content_transfer_encoding( val = nil )
-
default :content_transfer_encoding, val
-
end
-
-
1
def content_transfer_encoding=( val )
-
header[:content_transfer_encoding] = val
-
end
-
-
1
def content_type( val = nil )
-
4
default :content_type, val
-
end
-
-
1
def content_type=( val )
-
2
header[:content_type] = val
-
end
-
-
1
def date( val = nil )
-
default :date, val
-
end
-
-
1
def date=( val )
-
header[:date] = val
-
end
-
-
1
def transport_encoding( val = nil)
-
if val
-
self.transport_encoding = val
-
else
-
@transport_encoding
-
end
-
end
-
-
1
def transport_encoding=( val )
-
@transport_encoding = Mail::Encodings.get_encoding(val)
-
end
-
-
# Returns the From value of the mail object as an array of strings of
-
# address specs.
-
#
-
# Example:
-
#
-
# mail.from = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.from #=> ['mikel@test.lindsaar.net']
-
# mail.from = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.from 'Mikel <mikel@test.lindsaar.net>'
-
# mail.from #=> ['mikel@test.lindsaar.net']
-
#
-
# Additionally, you can append new addresses to the returned Array like
-
# object.
-
#
-
# Example:
-
#
-
# mail.from 'Mikel <mikel@test.lindsaar.net>'
-
# mail.from << 'ada@test.lindsaar.net'
-
# mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def from( val = nil )
-
1
default :from, val
-
end
-
-
# Sets the From value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.from = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.from #=> ['mikel@test.lindsaar.net']
-
# mail.from = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def from=( val )
-
header[:from] = val
-
end
-
-
1
def in_reply_to( val = nil )
-
default :in_reply_to, val
-
end
-
-
1
def in_reply_to=( val )
-
header[:in_reply_to] = val
-
end
-
-
1
def keywords( val = nil )
-
default :keywords, val
-
end
-
-
1
def keywords=( val )
-
header[:keywords] = val
-
end
-
-
# Returns the Message-ID of the mail object. Note, per RFC 2822 the Message ID
-
# consists of what is INSIDE the < > usually seen in the mail header, so this method
-
# will return only what is inside.
-
#
-
# Example:
-
#
-
# mail.message_id = '<1234@message.id>'
-
# mail.message_id #=> '1234@message.id'
-
#
-
# Also allows you to set the Message-ID by passing a string as a parameter
-
#
-
# mail.message_id '<1234@message.id>'
-
# mail.message_id #=> '1234@message.id'
-
1
def message_id( val = nil )
-
default :message_id, val
-
end
-
-
# Sets the Message-ID. Note, per RFC 2822 the Message ID consists of what is INSIDE
-
# the < > usually seen in the mail header, so this method will return only what is inside.
-
#
-
# mail.message_id = '<1234@message.id>'
-
# mail.message_id #=> '1234@message.id'
-
1
def message_id=( val )
-
header[:message_id] = val
-
end
-
-
# Returns the MIME version of the email as a string
-
#
-
# Example:
-
#
-
# mail.mime_version = '1.0'
-
# mail.mime_version #=> '1.0'
-
#
-
# Also allows you to set the MIME version by passing a string as a parameter.
-
#
-
# Example:
-
#
-
# mail.mime_version '1.0'
-
# mail.mime_version #=> '1.0'
-
1
def mime_version( val = nil )
-
default :mime_version, val
-
end
-
-
# Sets the MIME version of the email by accepting a string
-
#
-
# Example:
-
#
-
# mail.mime_version = '1.0'
-
# mail.mime_version #=> '1.0'
-
1
def mime_version=( val )
-
2
header[:mime_version] = val
-
end
-
-
1
def received( val = nil )
-
if val
-
header[:received] = val
-
else
-
header[:received]
-
end
-
end
-
-
1
def received=( val )
-
header[:received] = val
-
end
-
-
1
def references( val = nil )
-
default :references, val
-
end
-
-
1
def references=( val )
-
header[:references] = val
-
end
-
-
# Returns the Reply-To value of the mail object as an array of strings of
-
# address specs.
-
#
-
# Example:
-
#
-
# mail.reply_to = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.reply_to #=> ['mikel@test.lindsaar.net']
-
# mail.reply_to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.reply_to 'Mikel <mikel@test.lindsaar.net>'
-
# mail.reply_to #=> ['mikel@test.lindsaar.net']
-
#
-
# Additionally, you can append new addresses to the returned Array like
-
# object.
-
#
-
# Example:
-
#
-
# mail.reply_to 'Mikel <mikel@test.lindsaar.net>'
-
# mail.reply_to << 'ada@test.lindsaar.net'
-
# mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def reply_to( val = nil )
-
default :reply_to, val
-
end
-
-
# Sets the Reply-To value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.reply_to = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.reply_to #=> ['mikel@test.lindsaar.net']
-
# mail.reply_to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def reply_to=( val )
-
header[:reply_to] = val
-
end
-
-
# Returns the Resent-Bcc value of the mail object as an array of strings of
-
# address specs.
-
#
-
# Example:
-
#
-
# mail.resent_bcc = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_bcc #=> ['mikel@test.lindsaar.net']
-
# mail.resent_bcc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.resent_bcc 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_bcc #=> ['mikel@test.lindsaar.net']
-
#
-
# Additionally, you can append new addresses to the returned Array like
-
# object.
-
#
-
# Example:
-
#
-
# mail.resent_bcc 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_bcc << 'ada@test.lindsaar.net'
-
# mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def resent_bcc( val = nil )
-
default :resent_bcc, val
-
end
-
-
# Sets the Resent-Bcc value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.resent_bcc = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_bcc #=> ['mikel@test.lindsaar.net']
-
# mail.resent_bcc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def resent_bcc=( val )
-
header[:resent_bcc] = val
-
end
-
-
# Returns the Resent-Cc value of the mail object as an array of strings of
-
# address specs.
-
#
-
# Example:
-
#
-
# mail.resent_cc = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_cc #=> ['mikel@test.lindsaar.net']
-
# mail.resent_cc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.resent_cc 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_cc #=> ['mikel@test.lindsaar.net']
-
#
-
# Additionally, you can append new addresses to the returned Array like
-
# object.
-
#
-
# Example:
-
#
-
# mail.resent_cc 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_cc << 'ada@test.lindsaar.net'
-
# mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def resent_cc( val = nil )
-
default :resent_cc, val
-
end
-
-
# Sets the Resent-Cc value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.resent_cc = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_cc #=> ['mikel@test.lindsaar.net']
-
# mail.resent_cc = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def resent_cc=( val )
-
header[:resent_cc] = val
-
end
-
-
1
def resent_date( val = nil )
-
default :resent_date, val
-
end
-
-
1
def resent_date=( val )
-
header[:resent_date] = val
-
end
-
-
# Returns the Resent-From value of the mail object as an array of strings of
-
# address specs.
-
#
-
# Example:
-
#
-
# mail.resent_from = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_from #=> ['mikel@test.lindsaar.net']
-
# mail.resent_from = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.resent_from ['Mikel <mikel@test.lindsaar.net>']
-
# mail.resent_from #=> 'mikel@test.lindsaar.net'
-
#
-
# Additionally, you can append new addresses to the returned Array like
-
# object.
-
#
-
# Example:
-
#
-
# mail.resent_from 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_from << 'ada@test.lindsaar.net'
-
# mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def resent_from( val = nil )
-
default :resent_from, val
-
end
-
-
# Sets the Resent-From value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.resent_from = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_from #=> ['mikel@test.lindsaar.net']
-
# mail.resent_from = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def resent_from=( val )
-
header[:resent_from] = val
-
end
-
-
1
def resent_message_id( val = nil )
-
default :resent_message_id, val
-
end
-
-
1
def resent_message_id=( val )
-
header[:resent_message_id] = val
-
end
-
-
# Returns the Resent-Sender value of the mail object, as a single string of an address
-
# spec. A sender per RFC 2822 must be a single address, so you can not append to
-
# this address.
-
#
-
# Example:
-
#
-
# mail.resent_sender = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_sender #=> 'mikel@test.lindsaar.net'
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.resent_sender 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_sender #=> 'mikel@test.lindsaar.net'
-
1
def resent_sender( val = nil )
-
default :resent_sender, val
-
end
-
-
# Sets the Resent-Sender value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.resent_sender = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_sender #=> 'mikel@test.lindsaar.net'
-
1
def resent_sender=( val )
-
header[:resent_sender] = val
-
end
-
-
# Returns the Resent-To value of the mail object as an array of strings of
-
# address specs.
-
#
-
# Example:
-
#
-
# mail.resent_to = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_to #=> ['mikel@test.lindsaar.net']
-
# mail.resent_to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.resent_to 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_to #=> ['mikel@test.lindsaar.net']
-
#
-
# Additionally, you can append new addresses to the returned Array like
-
# object.
-
#
-
# Example:
-
#
-
# mail.resent_to 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_to << 'ada@test.lindsaar.net'
-
# mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def resent_to( val = nil )
-
default :resent_to, val
-
end
-
-
# Sets the Resent-To value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.resent_to = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.resent_to #=> ['mikel@test.lindsaar.net']
-
# mail.resent_to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def resent_to=( val )
-
header[:resent_to] = val
-
end
-
-
# Returns the return path of the mail object, or sets it if you pass a string
-
1
def return_path( val = nil )
-
default :return_path, val
-
end
-
-
# Sets the return path of the object
-
1
def return_path=( val )
-
header[:return_path] = val
-
end
-
-
# Returns the Sender value of the mail object, as a single string of an address
-
# spec. A sender per RFC 2822 must be a single address.
-
#
-
# Example:
-
#
-
# mail.sender = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.sender #=> 'mikel@test.lindsaar.net'
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.sender 'Mikel <mikel@test.lindsaar.net>'
-
# mail.sender #=> 'mikel@test.lindsaar.net'
-
1
def sender( val = nil )
-
default :sender, val
-
end
-
-
# Sets the Sender value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.sender = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.sender #=> 'mikel@test.lindsaar.net'
-
1
def sender=( val )
-
header[:sender] = val
-
end
-
-
# Returns the SMTP Envelope From value of the mail object, as a single
-
# string of an address spec.
-
#
-
# Defaults to Return-Path, Sender, or the first From address.
-
#
-
# Example:
-
#
-
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.smtp_envelope_from 'Mikel <mikel@test.lindsaar.net>'
-
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
-
1
def smtp_envelope_from( val = nil )
-
if val
-
self.smtp_envelope_from = val
-
else
-
@smtp_envelope_from || return_path || sender || from_addrs.first
-
end
-
end
-
-
# Sets the From address on the SMTP Envelope.
-
#
-
# Example:
-
#
-
# mail.smtp_envelope_from = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.smtp_envelope_from #=> 'mikel@test.lindsaar.net'
-
1
def smtp_envelope_from=( val )
-
@smtp_envelope_from = val
-
end
-
-
# Returns the SMTP Envelope To value of the mail object.
-
#
-
# Defaults to #destinations: To, Cc, and Bcc addresses.
-
#
-
# Example:
-
#
-
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.smtp_envelope_to ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
-
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
-
1
def smtp_envelope_to( val = nil )
-
if val
-
self.smtp_envelope_to = val
-
else
-
@smtp_envelope_to || destinations
-
end
-
end
-
-
# Sets the To addresses on the SMTP Envelope.
-
#
-
# Example:
-
#
-
# mail.smtp_envelope_to = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.smtp_envelope_to #=> 'mikel@test.lindsaar.net'
-
#
-
# mail.smtp_envelope_to = ['Mikel <mikel@test.lindsaar.net>', 'Lindsaar <lindsaar@test.lindsaar.net>']
-
# mail.smtp_envelope_to #=> ['mikel@test.lindsaar.net', 'lindsaar@test.lindsaar.net']
-
1
def smtp_envelope_to=( val )
-
@smtp_envelope_to =
-
case val
-
when Array, NilClass
-
val
-
else
-
[val]
-
end
-
end
-
-
# Returns the decoded value of the subject field, as a single string.
-
#
-
# Example:
-
#
-
# mail.subject = "G'Day mate"
-
# mail.subject #=> "G'Day mate"
-
# mail.subject = '=?UTF-8?Q?This_is_=E3=81=82_string?='
-
# mail.subject #=> "This is あ string"
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.subject "G'Day mate"
-
# mail.subject #=> "G'Day mate"
-
1
def subject( val = nil )
-
1
default :subject, val
-
end
-
-
# Sets the Subject value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.subject = '=?UTF-8?Q?This_is_=E3=81=82_string?='
-
# mail.subject #=> "This is あ string"
-
1
def subject=( val )
-
header[:subject] = val
-
end
-
-
# Returns the To value of the mail object as an array of strings of
-
# address specs.
-
#
-
# Example:
-
#
-
# mail.to = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.to #=> ['mikel@test.lindsaar.net']
-
# mail.to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
#
-
# Also allows you to set the value by passing a value as a parameter
-
#
-
# Example:
-
#
-
# mail.to 'Mikel <mikel@test.lindsaar.net>'
-
# mail.to #=> ['mikel@test.lindsaar.net']
-
#
-
# Additionally, you can append new addresses to the returned Array like
-
# object.
-
#
-
# Example:
-
#
-
# mail.to 'Mikel <mikel@test.lindsaar.net>'
-
# mail.to << 'ada@test.lindsaar.net'
-
# mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def to( val = nil )
-
1
default :to, val
-
end
-
-
# Sets the To value of the mail object, pass in a string of the field
-
#
-
# Example:
-
#
-
# mail.to = 'Mikel <mikel@test.lindsaar.net>'
-
# mail.to #=> ['mikel@test.lindsaar.net']
-
# mail.to = 'Mikel <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
-
# mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
-
1
def to=( val )
-
header[:to] = val
-
end
-
-
# Returns the default value of the field requested as a symbol.
-
#
-
# Each header field has a :default method which returns the most common use case for
-
# that field, for example, the date field types will return a DateTime object when
-
# sent :default, the subject, or unstructured fields will return a decoded string of
-
# their value, the address field types will return a single addr_spec or an array of
-
# addr_specs if there is more than one.
-
1
def default( sym, val = nil )
-
7
if val
-
2
header[sym] = val
-
else
-
5
header[sym].default if header[sym]
-
end
-
end
-
-
# Sets the body object of the message object.
-
#
-
# Example:
-
#
-
# mail.body = 'This is the body'
-
# mail.body #=> #<Mail::Body:0x13919c @raw_source="This is the bo...
-
#
-
# You can also reset the body of an Message object by setting body to nil
-
#
-
# Example:
-
#
-
# mail.body = 'this is the body'
-
# mail.body.encoded #=> 'this is the body'
-
# mail.body = nil
-
# mail.body.encoded #=> ''
-
#
-
# If you try and set the body of an email that is a multipart email, then instead
-
# of deleting all the parts of your email, mail will add a text/plain part to
-
# your email:
-
#
-
# mail.add_file 'somefilename.png'
-
# mail.parts.length #=> 1
-
# mail.body = "This is a body"
-
# mail.parts.length #=> 2
-
# mail.parts.last.content_type.content_type #=> 'This is a body'
-
1
def body=(value)
-
6
body_lazy(value)
-
end
-
-
# Returns the body of the message object. Or, if passed
-
# a parameter sets the value.
-
#
-
# Example:
-
#
-
# mail = Mail::Message.new('To: mikel\r\n\r\nThis is the body')
-
# mail.body #=> #<Mail::Body:0x13919c @raw_source="This is the bo...
-
#
-
# mail.body 'This is another body'
-
# mail.body #=> #<Mail::Body:0x13919c @raw_source="This is anothe...
-
1
def body(value = nil)
-
5
if value
-
self.body = value
-
# add_encoding_to_body
-
else
-
5
process_body_raw if @body_raw
-
5
@body
-
end
-
end
-
-
1
def body_encoding(value)
-
if value.nil?
-
body.encoding
-
else
-
body.encoding = value
-
end
-
end
-
-
1
def body_encoding=(value)
-
body.encoding = value
-
end
-
-
# Returns the list of addresses this message should be sent to by
-
# collecting the addresses off the to, cc and bcc fields.
-
#
-
# Example:
-
#
-
# mail.to = 'mikel@test.lindsaar.net'
-
# mail.cc = 'sam@test.lindsaar.net'
-
# mail.bcc = 'bob@test.lindsaar.net'
-
# mail.destinations.length #=> 3
-
# mail.destinations.first #=> 'mikel@test.lindsaar.net'
-
1
def destinations
-
[to_addrs, cc_addrs, bcc_addrs].compact.flatten
-
end
-
-
# Returns an array of addresses (the encoded value) in the From field,
-
# if no From field, returns an empty array
-
1
def from_addrs
-
from ? [from].flatten : []
-
end
-
-
# Returns an array of addresses (the encoded value) in the To field,
-
# if no To field, returns an empty array
-
1
def to_addrs
-
to ? [to].flatten : []
-
end
-
-
# Returns an array of addresses (the encoded value) in the Cc field,
-
# if no Cc field, returns an empty array
-
1
def cc_addrs
-
cc ? [cc].flatten : []
-
end
-
-
# Returns an array of addresses (the encoded value) in the Bcc field,
-
# if no Bcc field, returns an empty array
-
1
def bcc_addrs
-
bcc ? [bcc].flatten : []
-
end
-
-
# Allows you to add an arbitrary header
-
#
-
# Example:
-
#
-
# mail['foo'] = '1234'
-
# mail['foo'].to_s #=> '1234'
-
1
def []=(name, value)
-
14
if name.to_s == 'body'
-
2
self.body = value
-
12
elsif name.to_s =~ /content[-_]type/i
-
2
header[name] = value
-
10
elsif name.to_s == 'charset'
-
2
self.charset = value
-
else
-
8
header[name] = value
-
end
-
end
-
-
# Allows you to read an arbitrary header
-
#
-
# Example:
-
#
-
# mail['foo'] = '1234'
-
# mail['foo'].to_s #=> '1234'
-
1
def [](name)
-
header[underscoreize(name)]
-
end
-
-
# Method Missing in this implementation allows you to set any of the
-
# standard fields directly as you would the "to", "subject" etc.
-
#
-
# Those fields used most often (to, subject et al) are given their
-
# own method for ease of documentation and also to avoid the hook
-
# call to method missing.
-
#
-
# This will only catch the known fields listed in:
-
#
-
# Mail::Field::KNOWN_FIELDS
-
#
-
# as per RFC 2822, any ruby string or method name could pretty much
-
# be a field name, so we don't want to just catch ANYTHING sent to
-
# a message object and interpret it as a header.
-
#
-
# This method provides all three types of header call to set, read
-
# and explicitly set with the = operator
-
#
-
# Examples:
-
#
-
# mail.comments = 'These are some comments'
-
# mail.comments #=> 'These are some comments'
-
#
-
# mail.comments 'These are other comments'
-
# mail.comments #=> 'These are other comments'
-
#
-
#
-
# mail.date = 'Tue, 1 Jul 2003 10:52:37 +0200'
-
# mail.date.to_s #=> 'Tue, 1 Jul 2003 10:52:37 +0200'
-
#
-
# mail.date 'Tue, 1 Jul 2003 10:52:37 +0200'
-
# mail.date.to_s #=> 'Tue, 1 Jul 2003 10:52:37 +0200'
-
#
-
#
-
# mail.resent_msg_id = '<1234@resent_msg_id.lindsaar.net>'
-
# mail.resent_msg_id #=> '<1234@resent_msg_id.lindsaar.net>'
-
#
-
# mail.resent_msg_id '<4567@resent_msg_id.lindsaar.net>'
-
# mail.resent_msg_id #=> '<4567@resent_msg_id.lindsaar.net>'
-
1
def method_missing(name, *args, &block)
-
#:nodoc:
-
# Only take the structured fields, as we could take _anything_ really
-
# as it could become an optional field... "but therin lies the dark side"
-
field_name = underscoreize(name).chomp("=")
-
if Mail::Field::KNOWN_FIELDS.include?(field_name)
-
if args.empty?
-
header[field_name]
-
else
-
header[field_name] = args.first
-
end
-
else
-
super # otherwise pass it on
-
end
-
#:startdoc:
-
end
-
-
# Returns an FieldList of all the fields in the header in the order that
-
# they appear in the header
-
1
def header_fields
-
header.fields
-
end
-
-
# Returns true if the message has a message ID field, the field may or may
-
# not have a value, but the field exists or not.
-
1
def has_message_id?
-
header.has_message_id?
-
end
-
-
# Returns true if the message has a Date field, the field may or may
-
# not have a value, but the field exists or not.
-
1
def has_date?
-
header.has_date?
-
end
-
-
# Returns true if the message has a Date field, the field may or may
-
# not have a value, but the field exists or not.
-
1
def has_mime_version?
-
header.has_mime_version?
-
end
-
-
1
def has_content_type?
-
14
tmp = header[:content_type].main_type rescue nil
-
14
!!tmp
-
end
-
-
1
def has_charset?
-
tmp = header[:content_type].parameters rescue nil
-
!!(has_content_type? && tmp && tmp['charset'])
-
end
-
-
1
def has_content_transfer_encoding?
-
6
header[:content_transfer_encoding] && header[:content_transfer_encoding].errors.blank?
-
end
-
-
1
def has_transfer_encoding? # :nodoc:
-
STDERR.puts(":has_transfer_encoding? is deprecated in Mail 1.4.3. Please use has_content_transfer_encoding?\n#{caller}")
-
has_content_transfer_encoding?
-
end
-
-
# Creates a new empty Message-ID field and inserts it in the correct order
-
# into the Header. The MessageIdField object will automatically generate
-
# a unique message ID if you try and encode it or output it to_s without
-
# specifying a message id.
-
#
-
# It will preserve the message ID you specify if you do.
-
1
def add_message_id(msg_id_val = '')
-
header['message-id'] = msg_id_val
-
end
-
-
# Creates a new empty Date field and inserts it in the correct order
-
# into the Header. The DateField object will automatically generate
-
# DateTime.now's date if you try and encode it or output it to_s without
-
# specifying a date yourself.
-
#
-
# It will preserve any date you specify if you do.
-
1
def add_date(date_val = '')
-
header['date'] = date_val
-
end
-
-
# Creates a new empty Mime Version field and inserts it in the correct order
-
# into the Header. The MimeVersion object will automatically generate
-
# set itself to '1.0' if you try and encode it or output it to_s without
-
# specifying a version yourself.
-
#
-
# It will preserve any date you specify if you do.
-
1
def add_mime_version(ver_val = '')
-
header['mime-version'] = ver_val
-
end
-
-
# Adds a content type and charset if the body is US-ASCII
-
#
-
# Otherwise raises a warning
-
1
def add_content_type
-
header[:content_type] = 'text/plain'
-
end
-
-
# Adds a content type and charset if the body is US-ASCII
-
#
-
# Otherwise raises a warning
-
1
def add_charset
-
if !body.empty?
-
# Only give a warning if this isn't an attachment, has non US-ASCII and the user
-
# has not specified an encoding explicitly.
-
if @defaulted_charset && body.raw_source.not_ascii_only? && !self.attachment?
-
warning = "Non US-ASCII detected and no charset defined.\nDefaulting to UTF-8, set your own if this is incorrect.\n"
-
STDERR.puts(warning)
-
end
-
header[:content_type].parameters['charset'] = @charset
-
end
-
end
-
-
# Adds a content transfer encoding
-
#
-
# Otherwise raises a warning
-
1
def add_content_transfer_encoding
-
if body.only_us_ascii?
-
header[:content_transfer_encoding] = '7bit'
-
else
-
warning = "Non US-ASCII detected and no content-transfer-encoding defined.\nDefaulting to 8bit, set your own if this is incorrect.\n"
-
STDERR.puts(warning)
-
header[:content_transfer_encoding] = '8bit'
-
end
-
end
-
-
1
def add_transfer_encoding # :nodoc:
-
STDERR.puts(":add_transfer_encoding is deprecated in Mail 1.4.3. Please use add_content_transfer_encoding\n#{caller}")
-
add_content_transfer_encoding
-
end
-
-
1
def transfer_encoding # :nodoc:
-
STDERR.puts(":transfer_encoding is deprecated in Mail 1.4.3. Please use content_transfer_encoding\n#{caller}")
-
content_transfer_encoding
-
end
-
-
# Returns the MIME media type of part we are on, this is taken from the content-type header
-
1
def mime_type
-
has_content_type? ? header[:content_type].string : nil rescue nil
-
end
-
-
1
def message_content_type
-
STDERR.puts(":message_content_type is deprecated in Mail 1.4.3. Please use mime_type\n#{caller}")
-
mime_type
-
end
-
-
# Returns the character set defined in the content type field
-
1
def charset
-
4
if @header
-
has_content_type? ? content_type_parameters['charset'] : @charset
-
else
-
4
@charset
-
end
-
end
-
-
# Sets the charset to the supplied value.
-
1
def charset=(value)
-
6
@defaulted_charset = false
-
6
@charset = value
-
6
@header.charset = value
-
end
-
-
# Returns the main content type
-
1
def main_type
-
4
has_content_type? ? header[:content_type].main_type : nil rescue nil
-
end
-
-
# Returns the sub content type
-
1
def sub_type
-
has_content_type? ? header[:content_type].sub_type : nil rescue nil
-
end
-
-
# Returns the content type parameters
-
1
def mime_parameters
-
STDERR.puts(':mime_parameters is deprecated in Mail 1.4.3, please use :content_type_parameters instead')
-
content_type_parameters
-
end
-
-
# Returns the content type parameters
-
1
def content_type_parameters
-
2
has_content_type? ? header[:content_type].parameters : nil rescue nil
-
end
-
-
# Returns true if the message is multipart
-
1
def multipart?
-
8
has_content_type? ? !!(main_type =~ /^multipart$/i) : false
-
end
-
-
# Returns true if the message is a multipart/report
-
1
def multipart_report?
-
multipart? && sub_type =~ /^report$/i
-
end
-
-
# Returns true if the message is a multipart/report; report-type=delivery-status;
-
1
def delivery_status_report?
-
multipart_report? && content_type_parameters['report-type'] =~ /^delivery-status$/i
-
end
-
-
# returns the part in a multipart/report email that has the content-type delivery-status
-
1
def delivery_status_part
-
@delivery_stats_part ||= parts.select { |p| p.delivery_status_report_part? }.first
-
end
-
-
1
def bounced?
-
delivery_status_part and delivery_status_part.bounced?
-
end
-
-
1
def action
-
delivery_status_part and delivery_status_part.action
-
end
-
-
1
def final_recipient
-
delivery_status_part and delivery_status_part.final_recipient
-
end
-
-
1
def error_status
-
delivery_status_part and delivery_status_part.error_status
-
end
-
-
1
def diagnostic_code
-
delivery_status_part and delivery_status_part.diagnostic_code
-
end
-
-
1
def remote_mta
-
delivery_status_part and delivery_status_part.remote_mta
-
end
-
-
1
def retryable?
-
delivery_status_part and delivery_status_part.retryable?
-
end
-
-
# Returns the current boundary for this message part
-
1
def boundary
-
content_type_parameters ? content_type_parameters['boundary'] : nil
-
end
-
-
# Returns a parts list object of all the parts in the message
-
1
def parts
-
4
body.parts
-
end
-
-
# Returns an AttachmentsList object, which holds all of the attachments in
-
# the receiver object (either the entier email or a part within) and all
-
# of its descendants.
-
#
-
# It also allows you to add attachments to the mail object directly, like so:
-
#
-
# mail.attachments['filename.jpg'] = File.read('/path/to/filename.jpg')
-
#
-
# If you do this, then Mail will take the file name and work out the MIME media type
-
# set the Content-Type, Content-Disposition, Content-Transfer-Encoding and
-
# base64 encode the contents of the attachment all for you.
-
#
-
# You can also specify overrides if you want by passing a hash instead of a string:
-
#
-
# mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip',
-
# :content => File.read('/path/to/filename.jpg')}
-
#
-
# If you want to use a different encoding than Base64, you can pass an encoding in,
-
# but then it is up to you to pass in the content pre-encoded, and don't expect
-
# Mail to know how to decode this data:
-
#
-
# file_content = SpecialEncode(File.read('/path/to/filename.jpg'))
-
# mail.attachments['filename.jpg'] = {:mime_type => 'application/x-gzip',
-
# :encoding => 'SpecialEncoding',
-
# :content => file_content }
-
#
-
# You can also search for specific attachments:
-
#
-
# # By Filename
-
# mail.attachments['filename.jpg'] #=> Mail::Part object or nil
-
#
-
# # or by index
-
# mail.attachments[0] #=> Mail::Part (first attachment)
-
#
-
1
def attachments
-
4
parts.attachments
-
end
-
-
1
def has_attachments?
-
4
!attachments.empty?
-
end
-
-
# Accessor for html_part
-
1
def html_part(&block)
-
if block_given?
-
self.html_part = Mail::Part.new(:content_type => 'text/html', &block)
-
else
-
@html_part || find_first_mime_type('text/html')
-
end
-
end
-
-
# Accessor for text_part
-
1
def text_part(&block)
-
if block_given?
-
self.text_part = Mail::Part.new(:content_type => 'text/plain', &block)
-
else
-
@text_part || find_first_mime_type('text/plain')
-
end
-
end
-
-
# Helper to add a html part to a multipart/alternative email. If this and
-
# text_part are both defined in a message, then it will be a multipart/alternative
-
# message and set itself that way.
-
1
def html_part=(msg)
-
# Assign the html part and set multipart/alternative if there's a text part.
-
if msg
-
@html_part = msg
-
@html_part.content_type = 'text/html' unless @html_part.has_content_type?
-
add_multipart_alternate_header if text_part
-
add_part @html_part
-
-
# If nil, delete the html part and back out of multipart/alternative.
-
elsif @html_part
-
parts.delete_if { |p| p.object_id == @html_part.object_id }
-
@html_part = nil
-
if text_part
-
self.content_type = nil
-
body.boundary = nil
-
end
-
end
-
end
-
-
# Helper to add a text part to a multipart/alternative email. If this and
-
# html_part are both defined in a message, then it will be a multipart/alternative
-
# message and set itself that way.
-
1
def text_part=(msg)
-
# Assign the text part and set multipart/alternative if there's an html part.
-
if msg
-
@text_part = msg
-
@text_part.content_type = 'text/plain' unless @text_part.has_content_type?
-
add_multipart_alternate_header if html_part
-
add_part @text_part
-
-
# If nil, delete the text part and back out of multipart/alternative.
-
elsif @text_part
-
parts.delete_if { |p| p.object_id == @text_part.object_id }
-
@text_part = nil
-
if html_part
-
self.content_type = nil
-
body.boundary = nil
-
end
-
end
-
end
-
-
# Adds a part to the parts list or creates the part list
-
1
def add_part(part)
-
if !body.multipart? && !self.body.decoded.blank?
-
@text_part = Mail::Part.new('Content-Type: text/plain;')
-
@text_part.body = body.decoded
-
self.body << @text_part
-
add_multipart_alternate_header
-
end
-
add_boundary
-
self.body << part
-
end
-
-
# Allows you to add a part in block form to an existing mail message object
-
#
-
# Example:
-
#
-
# mail = Mail.new do
-
# part :content_type => "multipart/alternative", :content_disposition => "inline" do |p|
-
# p.part :content_type => "text/plain", :body => "test text\nline #2"
-
# p.part :content_type => "text/html", :body => "<b>test</b> HTML<br/>\nline #2"
-
# end
-
# end
-
1
def part(params = {})
-
new_part = Part.new(params)
-
yield new_part if block_given?
-
add_part(new_part)
-
end
-
-
# Adds a file to the message. You have two options with this method, you can
-
# just pass in the absolute path to the file you want and Mail will read the file,
-
# get the filename from the path you pass in and guess the MIME media type, or you
-
# can pass in the filename as a string, and pass in the file content as a blob.
-
#
-
# Example:
-
#
-
# m = Mail.new
-
# m.add_file('/path/to/filename.png')
-
#
-
# m = Mail.new
-
# m.add_file(:filename => 'filename.png', :content => File.read('/path/to/file.jpg'))
-
#
-
# Note also that if you add a file to an existing message, Mail will convert that message
-
# to a MIME multipart email, moving whatever plain text body you had into its own text
-
# plain part.
-
#
-
# Example:
-
#
-
# m = Mail.new do
-
# body 'this is some text'
-
# end
-
# m.multipart? #=> false
-
# m.add_file('/path/to/filename.png')
-
# m.multipart? #=> true
-
# m.parts.first.content_type.content_type #=> 'text/plain'
-
# m.parts.last.content_type.content_type #=> 'image/png'
-
#
-
# See also #attachments
-
1
def add_file(values)
-
convert_to_multipart unless self.multipart? || self.body.decoded.blank?
-
add_multipart_mixed_header
-
if values.is_a?(String)
-
basename = File.basename(values)
-
filedata = File.open(values, 'rb') { |f| f.read }
-
else
-
basename = values[:filename]
-
filedata = values[:content] || File.open(values[:filename], 'rb') { |f| f.read }
-
end
-
self.attachments[basename] = filedata
-
end
-
-
1
def convert_to_multipart
-
text = body.decoded
-
self.body = ''
-
text_part = Mail::Part.new({:content_type => 'text/plain;',
-
:body => text})
-
text_part.charset = charset unless @defaulted_charset
-
self.body << text_part
-
end
-
-
# Encodes the message, calls encode on all its parts, gets an email message
-
# ready to send
-
1
def ready_to_send!
-
identify_and_set_transfer_encoding
-
parts.sort!([ "text/plain", "text/enriched", "text/html", "multipart/alternative" ])
-
parts.each do |part|
-
part.transport_encoding = transport_encoding
-
part.ready_to_send!
-
end
-
add_required_fields
-
end
-
-
1
def encode!
-
STDERR.puts("Deprecated in 1.1.0 in favour of :ready_to_send! as it is less confusing with encoding and decoding.")
-
ready_to_send!
-
end
-
-
# Outputs an encoded string representation of the mail message including
-
# all headers, attachments, etc. This is an encoded email in US-ASCII,
-
# so it is able to be directly sent to an email server.
-
1
def encoded
-
ready_to_send!
-
buffer = header.encoded
-
buffer << "\r\n"
-
buffer << body.encoded(content_transfer_encoding)
-
buffer
-
end
-
-
1
def without_attachments!
-
return self unless has_attachments?
-
-
parts.delete_if { |p| p.attachment? }
-
body_raw = if parts.empty?
-
''
-
else
-
body.encoded
-
end
-
-
@body = Mail::Body.new(body_raw)
-
-
self
-
end
-
-
1
def to_yaml(opts = {})
-
hash = {}
-
hash['headers'] = {}
-
header.fields.each do |field|
-
hash['headers'][field.name] = field.value
-
end
-
hash['delivery_handler'] = delivery_handler.to_s if delivery_handler
-
hash['transport_encoding'] = transport_encoding.to_s
-
special_variables = [:@header, :@delivery_handler, :@transport_encoding]
-
if multipart?
-
hash['multipart_body'] = []
-
body.parts.map { |part| hash['multipart_body'] << part.to_yaml }
-
special_variables.push(:@body, :@text_part, :@html_part)
-
end
-
(instance_variables.map(&:to_sym) - special_variables).each do |var|
-
hash[var.to_s] = instance_variable_get(var)
-
end
-
hash.to_yaml(opts)
-
end
-
-
1
def self.from_yaml(str)
-
hash = YAML.load(str)
-
m = self.new(:headers => hash['headers'])
-
hash.delete('headers')
-
hash.each do |k,v|
-
case
-
when k == 'delivery_handler'
-
begin
-
m.delivery_handler = Object.const_get(v) unless v.blank?
-
rescue NameError
-
end
-
when k == 'transport_encoding'
-
m.transport_encoding(v)
-
when k == 'multipart_body'
-
v.map {|part| m.add_part Mail::Part.from_yaml(part) }
-
when k =~ /^@/
-
m.instance_variable_set(k.to_sym, v)
-
end
-
end
-
m
-
end
-
-
1
def self.from_hash(hash)
-
Mail::Message.new(hash)
-
end
-
-
1
def to_s
-
encoded
-
end
-
-
1
def inspect
-
"#<#{self.class}:#{self.object_id}, Multipart: #{multipart?}, Headers: #{header.field_summary}>"
-
end
-
-
1
def decoded
-
case
-
when self.text?
-
decode_body_as_text
-
when self.attachment?
-
decode_body
-
when !self.multipart?
-
body.decoded
-
else
-
raise NoMethodError, 'Can not decode an entire message, try calling #decoded on the various fields and body or parts if it is a multipart message.'
-
end
-
end
-
-
1
def read
-
if self.attachment?
-
decode_body
-
else
-
raise NoMethodError, 'Can not call read on a part unless it is an attachment.'
-
end
-
end
-
-
1
def decode_body
-
body.decoded
-
end
-
-
# Returns true if this part is an attachment,
-
# false otherwise.
-
1
def attachment?
-
!!find_attachment
-
end
-
-
# Returns the attachment data if there is any
-
1
def attachment
-
@attachment
-
end
-
-
# Returns the filename of the attachment
-
1
def filename
-
find_attachment
-
end
-
-
1
def all_parts
-
parts.map { |p| [p, p.all_parts] }.flatten
-
end
-
-
1
def find_first_mime_type(mt)
-
all_parts.detect { |p| p.mime_type == mt && !p.attachment? }
-
end
-
-
# Skips the deletion of this message. All other messages
-
# flagged for delete still will be deleted at session close (i.e. when
-
# #find exits). Only has an effect if you're using #find_and_delete
-
# or #find with :delete_after_find set to true.
-
1
def skip_deletion
-
@mark_for_delete = false
-
end
-
-
# Sets whether this message should be deleted at session close (i.e.
-
# after #find). Message will only be deleted if messages are retrieved
-
# using the #find_and_delete method, or by calling #find with
-
# :delete_after_find set to true.
-
1
def mark_for_delete=(value = true)
-
@mark_for_delete = value
-
end
-
-
# Returns whether message will be marked for deletion.
-
# If so, the message will be deleted at session close (i.e. after #find
-
# exits), but only if also using the #find_and_delete method, or by
-
# calling #find with :delete_after_find set to true.
-
#
-
# Side-note: Just to be clear, this method will return true even if
-
# the message hasn't yet been marked for delete on the mail server.
-
# However, if this method returns true, it *will be* marked on the
-
# server after each block yields back to #find or #find_and_delete.
-
1
def is_marked_for_delete?
-
return @mark_for_delete
-
end
-
-
1
def text?
-
has_content_type? ? !!(main_type =~ /^text$/i) : false
-
end
-
-
1
private
-
-
# 2.1. General Description
-
# A message consists of header fields (collectively called "the header
-
# of the message") followed, optionally, by a body. The header is a
-
# sequence of lines of characters with special syntax as defined in
-
# this standard. The body is simply a sequence of characters that
-
# follows the header and is separated from the header by an empty line
-
# (i.e., a line with nothing preceding the CRLF).
-
#
-
# Additionally, I allow for the case where someone might have put whitespace
-
# on the "gap line"
-
1
def parse_message
-
4
header_part, body_part = raw_source.lstrip.split(/#{CRLF}#{CRLF}|#{CRLF}#{WSP}*#{CRLF}(?!#{WSP})/m, 2)
-
4
self.header = header_part
-
4
self.body = body_part
-
end
-
-
1
def raw_source=(value)
-
4
value.force_encoding("binary") if RUBY_VERSION >= "1.9.1"
-
4
@raw_source = value.to_crlf
-
end
-
-
# see comments to body=. We take data and process it lazily
-
1
def body_lazy(value)
-
6
process_body_raw if @body_raw && value
-
case
-
when value == nil || value.length<=0
-
4
@body = Mail::Body.new('')
-
4
@body_raw = nil
-
4
add_encoding_to_body
-
when @body && @body.multipart?
-
@body << Mail::Part.new(value)
-
add_encoding_to_body
-
else
-
2
@body_raw = value
-
# process_body_raw
-
6
end
-
end
-
-
-
1
def process_body_raw
-
2
@body = Mail::Body.new(@body_raw)
-
2
@body_raw = nil
-
2
separate_parts if @separate_parts
-
-
2
add_encoding_to_body
-
end
-
-
1
def set_envelope_header
-
4
raw_string = raw_source.to_s
-
4
if match_data = raw_source.to_s.match(/\AFrom\s(#{TEXT}+)#{CRLF}/m)
-
set_envelope(match_data[1])
-
self.raw_source = raw_string.sub(match_data[0], "")
-
end
-
end
-
-
1
def separate_parts
-
body.split!(boundary)
-
end
-
-
1
def add_encoding_to_body
-
6
if has_content_transfer_encoding?
-
@body.encoding = content_transfer_encoding
-
end
-
end
-
-
1
def identify_and_set_transfer_encoding
-
if body && body.multipart?
-
self.content_transfer_encoding = @transport_encoding
-
else
-
self.content_transfer_encoding = body.get_best_encoding(@transport_encoding)
-
end
-
end
-
-
1
def add_required_fields
-
add_required_message_fields
-
add_multipart_mixed_header if body.multipart?
-
add_content_type unless has_content_type?
-
add_charset unless has_charset?
-
add_content_transfer_encoding unless has_content_transfer_encoding?
-
end
-
-
1
def add_required_message_fields
-
add_date unless has_date?
-
add_mime_version unless has_mime_version?
-
add_message_id unless has_message_id?
-
end
-
-
1
def add_multipart_alternate_header
-
header['content-type'] = ContentTypeField.with_boundary('multipart/alternative').value
-
header['content_type'].parameters[:charset] = @charset
-
body.boundary = boundary
-
end
-
-
1
def add_boundary
-
unless body.boundary && boundary
-
header['content-type'] = 'multipart/mixed' unless header['content-type']
-
header['content-type'].parameters[:boundary] = ContentTypeField.generate_boundary
-
header['content_type'].parameters[:charset] = @charset
-
body.boundary = boundary
-
end
-
end
-
-
1
def add_multipart_mixed_header
-
unless header['content-type']
-
header['content-type'] = ContentTypeField.with_boundary('multipart/mixed').value
-
header['content_type'].parameters[:charset] = @charset
-
body.boundary = boundary
-
end
-
end
-
-
1
def init_with_hash(hash)
-
passed_in_options = IndifferentHash.new(hash)
-
self.raw_source = ''
-
-
@header = Mail::Header.new
-
@body = Mail::Body.new
-
@body_raw = nil
-
-
# We need to store the body until last, as we need all headers added first
-
body_content = nil
-
-
passed_in_options.each_pair do |k,v|
-
k = underscoreize(k).to_sym if k.class == String
-
if k == :headers
-
self.headers(v)
-
elsif k == :body
-
body_content = v
-
else
-
self[k] = v
-
end
-
end
-
-
if body_content
-
self.body = body_content
-
if has_content_transfer_encoding?
-
body.encoding = content_transfer_encoding
-
end
-
end
-
end
-
-
1
def init_with_string(string)
-
4
self.raw_source = string
-
4
set_envelope_header
-
4
parse_message
-
4
@separate_parts = multipart?
-
end
-
-
# Returns the filename of the attachment (if it exists) or returns nil
-
1
def find_attachment
-
content_type_name = header[:content_type].filename rescue nil
-
content_disp_name = header[:content_disposition].filename rescue nil
-
content_loc_name = header[:content_location].location rescue nil
-
case
-
when content_type && content_type_name
-
filename = content_type_name
-
when content_disposition && content_disp_name
-
filename = content_disp_name
-
when content_location && content_loc_name
-
filename = content_loc_name
-
else
-
filename = nil
-
end
-
filename = Mail::Encodings.decode_encode(filename, :decode) if filename rescue filename
-
filename
-
end
-
-
1
def do_delivery
-
begin
-
if perform_deliveries
-
delivery_method.deliver!(self)
-
end
-
rescue Exception => e # Net::SMTP errors or sendmail pipe errors
-
raise e if raise_delivery_errors
-
end
-
end
-
-
1
def decode_body_as_text
-
body_text = decode_body
-
if charset
-
if RUBY_VERSION < '1.9'
-
require 'iconv'
-
return Iconv.conv("UTF-8//TRANSLIT//IGNORE", charset, body_text)
-
else
-
if encoding = Encoding.find(charset) rescue nil
-
body_text.force_encoding(encoding)
-
return body_text.encode(Encoding::UTF_8, :undef => :replace, :invalid => :replace, :replace => '')
-
end
-
end
-
end
-
body_text
-
end
-
-
end
-
end
-
1
require 'mail/network/retriever_methods/base'
-
-
1
module Mail
-
1
register_autoload :SMTP, 'mail/network/delivery_methods/smtp'
-
1
register_autoload :FileDelivery, 'mail/network/delivery_methods/file_delivery'
-
1
register_autoload :Sendmail, 'mail/network/delivery_methods/sendmail'
-
1
register_autoload :Exim, 'mail/network/delivery_methods/exim'
-
1
register_autoload :SMTPConnection, 'mail/network/delivery_methods/smtp_connection'
-
1
register_autoload :TestMailer, 'mail/network/delivery_methods/test_mailer'
-
-
1
register_autoload :POP3, 'mail/network/retriever_methods/pop3'
-
1
register_autoload :IMAP, 'mail/network/retriever_methods/imap'
-
1
register_autoload :TestRetriever, 'mail/network/retriever_methods/test_retriever'
-
end
-
1
require 'mail/check_delivery_params'
-
-
1
module Mail
-
-
# FileDelivery class delivers emails into multiple files based on the destination
-
# address. Each file is appended to if it already exists.
-
#
-
# So if you have an email going to fred@test, bob@test, joe@anothertest, and you
-
# set your location path to /path/to/mails then FileDelivery will create the directory
-
# if it does not exist, and put one copy of the email in three files, called
-
# by their message id
-
#
-
# Make sure the path you specify with :location is writable by the Ruby process
-
# running Mail.
-
1
class FileDelivery
-
1
include Mail::CheckDeliveryParams
-
-
1
if RUBY_VERSION >= '1.9.1'
-
1
require 'fileutils'
-
else
-
require 'ftools'
-
end
-
-
1
def initialize(values)
-
self.settings = { :location => './mails' }.merge!(values)
-
end
-
-
1
attr_accessor :settings
-
-
1
def deliver!(mail)
-
check_delivery_params(mail)
-
-
if ::File.respond_to?(:makedirs)
-
::File.makedirs settings[:location]
-
else
-
::FileUtils.mkdir_p settings[:location]
-
end
-
-
mail.destinations.uniq.each do |to|
-
::File.open(::File.join(settings[:location], File.basename(to.to_s)), 'a') { |f| "#{f.write(mail.encoded)}\r\n\r\n" }
-
end
-
end
-
-
end
-
end
-
1
require 'mail/check_delivery_params'
-
-
1
module Mail
-
# A delivery method implementation which sends via sendmail.
-
#
-
# To use this, first find out where the sendmail binary is on your computer,
-
# if you are on a mac or unix box, it is usually in /usr/sbin/sendmail, this will
-
# be your sendmail location.
-
#
-
# Mail.defaults do
-
# delivery_method :sendmail
-
# end
-
#
-
# Or if your sendmail binary is not at '/usr/sbin/sendmail'
-
#
-
# Mail.defaults do
-
# delivery_method :sendmail, :location => '/absolute/path/to/your/sendmail'
-
# end
-
#
-
# Then just deliver the email as normal:
-
#
-
# Mail.deliver do
-
# to 'mikel@test.lindsaar.net'
-
# from 'ada@test.lindsaar.net'
-
# subject 'testing sendmail'
-
# body 'testing sendmail'
-
# end
-
#
-
# Or by calling deliver on a Mail message
-
#
-
# mail = Mail.new do
-
# to 'mikel@test.lindsaar.net'
-
# from 'ada@test.lindsaar.net'
-
# subject 'testing sendmail'
-
# body 'testing sendmail'
-
# end
-
#
-
# mail.deliver!
-
1
class Sendmail
-
1
include Mail::CheckDeliveryParams
-
-
1
def initialize(values)
-
self.settings = { :location => '/usr/sbin/sendmail',
-
:arguments => '-i' }.merge(values)
-
end
-
-
1
attr_accessor :settings
-
-
1
def deliver!(mail)
-
smtp_from, smtp_to, message = check_delivery_params(mail)
-
-
from = "-f #{self.class.shellquote(smtp_from)}"
-
to = smtp_to.map { |to| self.class.shellquote(to) }.join(' ')
-
-
arguments = "#{settings[:arguments]} #{from} --"
-
self.class.call(settings[:location], arguments, to, message)
-
end
-
-
1
def self.call(path, arguments, destinations, encoded_message)
-
popen "#{path} #{arguments} #{destinations}" do |io|
-
io.puts encoded_message.to_lf
-
io.flush
-
end
-
end
-
-
1
if RUBY_VERSION < '1.9.0'
-
def self.popen(command, &block)
-
IO.popen "#{command} 2>&1", 'w+', &block
-
end
-
else
-
1
def self.popen(command, &block)
-
IO.popen command, 'w+', :err => :out, &block
-
end
-
end
-
-
# The following is an adaptation of ruby 1.9.2's shellwords.rb file,
-
# it is modified to include '+' in the allowed list to allow for
-
# sendmail to accept email addresses as the sender with a + in them.
-
1
def self.shellquote(address)
-
# Process as a single byte sequence because not all shell
-
# implementations are multibyte aware.
-
#
-
# A LF cannot be escaped with a backslash because a backslash + LF
-
# combo is regarded as line continuation and simply ignored. Strip it.
-
escaped = address.gsub(/([^A-Za-z0-9_\s\+\-.,:\/@])/n, "\\\\\\1").gsub("\n", '')
-
%("#{escaped}")
-
end
-
end
-
end
-
1
require 'mail/check_delivery_params'
-
-
1
module Mail
-
# == Sending Email with SMTP
-
#
-
# Mail allows you to send emails using SMTP. This is done by wrapping Net::SMTP in
-
# an easy to use manner.
-
#
-
# === Sending via SMTP server on Localhost
-
#
-
# Sending locally (to a postfix or sendmail server running on localhost) requires
-
# no special setup. Just to Mail.deliver &block or message.deliver! and it will
-
# be sent in this method.
-
#
-
# === Sending via MobileMe
-
#
-
# Mail.defaults do
-
# delivery_method :smtp, { :address => "smtp.me.com",
-
# :port => 587,
-
# :domain => 'your.host.name',
-
# :user_name => '<username>',
-
# :password => '<password>',
-
# :authentication => 'plain',
-
# :enable_starttls_auto => true }
-
# end
-
#
-
# === Sending via GMail
-
#
-
# Mail.defaults do
-
# delivery_method :smtp, { :address => "smtp.gmail.com",
-
# :port => 587,
-
# :domain => 'your.host.name',
-
# :user_name => '<username>',
-
# :password => '<password>',
-
# :authentication => 'plain',
-
# :enable_starttls_auto => true }
-
# end
-
#
-
# === Certificate verification
-
#
-
# When using TLS, some mail servers provide certificates that are self-signed
-
# or whose names do not exactly match the hostname given in the address.
-
# OpenSSL will reject these by default. The best remedy is to use the correct
-
# hostname or update the certificate authorities trusted by your ruby. If
-
# that isn't possible, you can control this behavior with
-
# an :openssl_verify_mode setting. Its value may be either an OpenSSL
-
# verify mode constant (OpenSSL::SSL::VERIFY_NONE), or a string containing
-
# the name of an OpenSSL verify mode (none, peer, client_once,
-
# fail_if_no_peer_cert).
-
#
-
# === Others
-
#
-
# Feel free to send me other examples that were tricky
-
#
-
# === Delivering the email
-
#
-
# Once you have the settings right, sending the email is done by:
-
#
-
# Mail.deliver do
-
# to 'mikel@test.lindsaar.net'
-
# from 'ada@test.lindsaar.net'
-
# subject 'testing sendmail'
-
# body 'testing sendmail'
-
# end
-
#
-
# Or by calling deliver on a Mail message
-
#
-
# mail = Mail.new do
-
# to 'mikel@test.lindsaar.net'
-
# from 'ada@test.lindsaar.net'
-
# subject 'testing sendmail'
-
# body 'testing sendmail'
-
# end
-
#
-
# mail.deliver!
-
1
class SMTP
-
1
include Mail::CheckDeliveryParams
-
-
1
def initialize(values)
-
1
self.settings = { :address => "localhost",
-
:port => 25,
-
:domain => 'localhost.localdomain',
-
:user_name => nil,
-
:password => nil,
-
:authentication => nil,
-
:enable_starttls_auto => true,
-
:openssl_verify_mode => nil,
-
:ssl => nil,
-
:tls => nil
-
}.merge!(values)
-
end
-
-
1
attr_accessor :settings
-
-
# Send the message via SMTP.
-
# The from and to attributes are optional. If not set, they are retrieve from the Message.
-
1
def deliver!(mail)
-
smtp_from, smtp_to, message = check_delivery_params(mail)
-
-
smtp = Net::SMTP.new(settings[:address], settings[:port])
-
if settings[:tls] || settings[:ssl]
-
if smtp.respond_to?(:enable_tls)
-
smtp.enable_tls(ssl_context)
-
end
-
elsif settings[:enable_starttls_auto]
-
if smtp.respond_to?(:enable_starttls_auto)
-
smtp.enable_starttls_auto(ssl_context)
-
end
-
end
-
-
response = nil
-
smtp.start(settings[:domain], settings[:user_name], settings[:password], settings[:authentication]) do |smtp_obj|
-
response = smtp_obj.sendmail(message, smtp_from, smtp_to)
-
end
-
-
if settings[:return_response]
-
response
-
else
-
self
-
end
-
end
-
-
-
1
private
-
-
# Allow SSL context to be configured via settings, for Ruby >= 1.9
-
# Just returns openssl verify mode for Ruby 1.8.x
-
1
def ssl_context
-
openssl_verify_mode = settings[:openssl_verify_mode]
-
-
if openssl_verify_mode.kind_of?(String)
-
openssl_verify_mode = "OpenSSL::SSL::VERIFY_#{openssl_verify_mode.upcase}".constantize
-
end
-
-
if RUBY_VERSION < '1.9.0'
-
openssl_verify_mode
-
else
-
context = Net::SMTP.default_ssl_context
-
context.verify_mode = openssl_verify_mode
-
context.ca_path = settings[:ca_path] if settings[:ca_path]
-
context.ca_file = settings[:ca_file] if settings[:ca_file]
-
context
-
end
-
end
-
end
-
end
-
1
require 'mail/check_delivery_params'
-
-
1
module Mail
-
# The TestMailer is a bare bones mailer that does nothing. It is useful
-
# when you are testing.
-
#
-
# It also provides a template of the minimum methods you require to implement
-
# if you want to make a custom mailer for Mail
-
1
class TestMailer
-
1
include Mail::CheckDeliveryParams
-
-
# Provides a store of all the emails sent with the TestMailer so you can check them.
-
1
def TestMailer.deliveries
-
2
@@deliveries ||= []
-
end
-
-
# Allows you to over write the default deliveries store from an array to some
-
# other object. If you just want to clear the store,
-
# call TestMailer.deliveries.clear.
-
#
-
# If you place another object here, please make sure it responds to:
-
#
-
# * << (message)
-
# * clear
-
# * length
-
# * size
-
# * and other common Array methods
-
1
def TestMailer.deliveries=(val)
-
@@deliveries = val
-
end
-
-
1
def initialize(values)
-
2
@settings = values.dup
-
end
-
-
1
attr_accessor :settings
-
-
1
def deliver!(mail)
-
check_delivery_params(mail)
-
Mail::TestMailer.deliveries << mail
-
end
-
-
end
-
end
-
# encoding: utf-8
-
-
1
module Mail
-
-
1
class Retriever
-
-
# Get the oldest received email(s)
-
#
-
# Possible options:
-
# count: number of emails to retrieve. The default value is 1.
-
# order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
-
#
-
1
def first(options = {}, &block)
-
options ||= {}
-
options[:what] = :first
-
options[:count] ||= 1
-
find(options, &block)
-
end
-
-
# Get the most recent received email(s)
-
#
-
# Possible options:
-
# count: number of emails to retrieve. The default value is 1.
-
# order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
-
#
-
1
def last(options = {}, &block)
-
options ||= {}
-
options[:what] = :last
-
options[:count] ||= 1
-
find(options, &block)
-
end
-
-
# Get all emails.
-
#
-
# Possible options:
-
# order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
-
#
-
1
def all(options = {}, &block)
-
options ||= {}
-
options[:count] = :all
-
find(options, &block)
-
end
-
-
# Find emails in the mailbox, and then deletes them. Without any options, the
-
# five last received emails are returned.
-
#
-
# Possible options:
-
# what: last or first emails. The default is :first.
-
# order: order of emails returned. Possible values are :asc or :desc. Default value is :asc.
-
# count: number of emails to retrieve. The default value is 10. A value of 1 returns an
-
# instance of Message, not an array of Message instances.
-
# delete_after_find: flag for whether to delete each retreived email after find. Default
-
# is true. Call #find if you would like this to default to false.
-
#
-
1
def find_and_delete(options = {}, &block)
-
options ||= {}
-
options[:delete_after_find] ||= true
-
find(options, &block)
-
end
-
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module AddressLists
-
1
include Treetop::Runtime
-
-
1
def root
-
8
@root ||= :primary_address
-
end
-
-
1
include RFC2822
-
-
1
module PrimaryAddress0
-
1
def addresses
-
16
([first_addr] + other_addr.elements.map { |o| o.addr_value }).reject { |e| e.empty? }
-
end
-
end
-
-
1
module PrimaryAddress1
-
1
def addresses
-
[first_addr] + other_addr.elements.map { |o| o.addr_value }
-
end
-
end
-
-
1
def _nt_primary_address
-
8
start_index = index
-
8
if node_cache[:primary_address].has_key?(index)
-
cached = node_cache[:primary_address][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0 = index
-
8
r1 = _nt_address_list
-
8
r1.extend(PrimaryAddress0)
-
8
if r1
-
8
r0 = r1
-
else
-
r2 = _nt_obs_addr_list
-
r2.extend(PrimaryAddress1)
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
8
node_cache[:primary_address][start_index] = r0
-
-
8
r0
-
end
-
-
end
-
-
1
class AddressListsParser < Treetop::Runtime::CompiledParser
-
1
include AddressLists
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module ContentDisposition
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :content_disposition
-
end
-
-
1
include RFC2822
-
-
1
include RFC2045
-
-
1
module ContentDisposition0
-
1
def CFWS1
-
elements[0]
-
end
-
-
1
def parameter
-
elements[2]
-
end
-
-
1
def CFWS2
-
elements[3]
-
end
-
end
-
-
1
module ContentDisposition1
-
1
def disposition_type
-
elements[0]
-
end
-
-
1
def param_hashes
-
elements[1]
-
end
-
end
-
-
1
module ContentDisposition2
-
1
def parameters
-
param_hashes.elements.map do |param|
-
param.parameter.param_hash
-
end
-
end
-
end
-
-
1
def _nt_content_disposition
-
start_index = index
-
if node_cache[:content_disposition].has_key?(index)
-
cached = node_cache[:content_disposition][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_disposition_type
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
i3, s3 = index, []
-
r4 = _nt_CFWS
-
s3 << r4
-
if r4
-
if has_terminal?(";", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(";")
-
r5 = nil
-
end
-
s3 << r5
-
if r5
-
r6 = _nt_parameter
-
s3 << r6
-
if r6
-
r7 = _nt_CFWS
-
s3 << r7
-
end
-
end
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(ContentDisposition0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ContentDisposition1)
-
r0.extend(ContentDisposition2)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:content_disposition][start_index] = r0
-
-
r0
-
end
-
-
1
module DispositionType0
-
end
-
-
1
module DispositionType1
-
end
-
-
1
def _nt_disposition_type
-
start_index = index
-
if node_cache[:disposition_type].has_key?(index)
-
cached = node_cache[:disposition_type][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
if has_terminal?('\G[iI]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
s1 << r2
-
if r2
-
if has_terminal?('\G[nN]', true, index)
-
r3 = true
-
@index += 1
-
else
-
r3 = nil
-
end
-
s1 << r3
-
if r3
-
if has_terminal?('\G[lL]', true, index)
-
r4 = true
-
@index += 1
-
else
-
r4 = nil
-
end
-
s1 << r4
-
if r4
-
if has_terminal?('\G[iI]', true, index)
-
r5 = true
-
@index += 1
-
else
-
r5 = nil
-
end
-
s1 << r5
-
if r5
-
if has_terminal?('\G[nN]', true, index)
-
r6 = true
-
@index += 1
-
else
-
r6 = nil
-
end
-
s1 << r6
-
if r6
-
if has_terminal?('\G[eE]', true, index)
-
r7 = true
-
@index += 1
-
else
-
r7 = nil
-
end
-
s1 << r7
-
end
-
end
-
end
-
end
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(DispositionType0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
i8, s8 = index, []
-
if has_terminal?('\G[aA]', true, index)
-
r9 = true
-
@index += 1
-
else
-
r9 = nil
-
end
-
s8 << r9
-
if r9
-
if has_terminal?('\G[tT]', true, index)
-
r10 = true
-
@index += 1
-
else
-
r10 = nil
-
end
-
s8 << r10
-
if r10
-
if has_terminal?('\G[tT]', true, index)
-
r11 = true
-
@index += 1
-
else
-
r11 = nil
-
end
-
s8 << r11
-
if r11
-
if has_terminal?('\G[aA]', true, index)
-
r12 = true
-
@index += 1
-
else
-
r12 = nil
-
end
-
s8 << r12
-
if r12
-
if has_terminal?('\G[cC]', true, index)
-
r13 = true
-
@index += 1
-
else
-
r13 = nil
-
end
-
s8 << r13
-
if r13
-
if has_terminal?('\G[hH]', true, index)
-
r14 = true
-
@index += 1
-
else
-
r14 = nil
-
end
-
s8 << r14
-
if r14
-
if has_terminal?('\G[mM]', true, index)
-
r15 = true
-
@index += 1
-
else
-
r15 = nil
-
end
-
s8 << r15
-
if r15
-
if has_terminal?('\G[eE]', true, index)
-
r16 = true
-
@index += 1
-
else
-
r16 = nil
-
end
-
s8 << r16
-
if r16
-
if has_terminal?('\G[nN]', true, index)
-
r17 = true
-
@index += 1
-
else
-
r17 = nil
-
end
-
s8 << r17
-
if r17
-
if has_terminal?('\G[tT]', true, index)
-
r18 = true
-
@index += 1
-
else
-
r18 = nil
-
end
-
s8 << r18
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
if s8.last
-
r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
-
r8.extend(DispositionType1)
-
else
-
@index = i8
-
r8 = nil
-
end
-
if r8
-
r0 = r8
-
else
-
r19 = _nt_extension_token
-
if r19
-
r0 = r19
-
else
-
if has_terminal?('', false, index)
-
r20 = instantiate_node(SyntaxNode,input, index...(index + 0))
-
@index += 0
-
else
-
terminal_parse_failure('')
-
r20 = nil
-
end
-
if r20
-
r0 = r20
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
-
node_cache[:disposition_type][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_extension_token
-
start_index = index
-
if node_cache[:extension_token].has_key?(index)
-
cached = node_cache[:extension_token][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_ietf_token
-
if r1
-
r0 = r1
-
else
-
r2 = _nt_custom_x_token
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:extension_token][start_index] = r0
-
-
r0
-
end
-
-
1
module Parameter0
-
1
def attr
-
elements[1]
-
end
-
-
1
def val
-
elements[3]
-
end
-
-
end
-
-
1
module Parameter1
-
1
def param_hash
-
{attr.text_value => val.text_value}
-
end
-
end
-
-
1
def _nt_parameter
-
start_index = index
-
if node_cache[:parameter].has_key?(index)
-
cached = node_cache[:parameter][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
r3 = _nt_attribute
-
s0 << r3
-
if r3
-
if has_terminal?("=", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("=")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_value
-
s0 << r5
-
if r5
-
r7 = _nt_CFWS
-
if r7
-
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Parameter0)
-
r0.extend(Parameter1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:parameter][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_attribute
-
start_index = index
-
if node_cache[:attribute].has_key?(index)
-
cached = node_cache[:attribute][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
s0, i0 = [], index
-
loop do
-
r1 = _nt_token
-
if r1
-
s0 << r1
-
else
-
break
-
end
-
end
-
if s0.empty?
-
@index = i0
-
r0 = nil
-
else
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
node_cache[:attribute][start_index] = r0
-
-
r0
-
end
-
-
1
module Value0
-
1
def text_value
-
quoted_content.text_value
-
end
-
end
-
-
1
def _nt_value
-
start_index = index
-
if node_cache[:value].has_key?(index)
-
cached = node_cache[:value][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_quoted_string
-
r1.extend(Value0)
-
if r1
-
r0 = r1
-
else
-
s2, i2 = [], index
-
loop do
-
i3 = index
-
r4 = _nt_token
-
if r4
-
r3 = r4
-
else
-
if has_terminal?('\G[\\x3d]', true, index)
-
r5 = true
-
@index += 1
-
else
-
r5 = nil
-
end
-
if r5
-
r3 = r5
-
else
-
@index = i3
-
r3 = nil
-
end
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
if s2.empty?
-
@index = i2
-
r2 = nil
-
else
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
end
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:value][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class ContentDispositionParser < Treetop::Runtime::CompiledParser
-
1
include ContentDisposition
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module ContentLocation
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :primary
-
end
-
-
1
include RFC2822
-
-
1
include RFC2045
-
-
1
module Primary0
-
1
def CFWS1
-
elements[0]
-
end
-
-
1
def location
-
elements[1]
-
end
-
-
1
def CFWS2
-
elements[2]
-
end
-
end
-
-
1
def _nt_primary
-
start_index = index
-
if node_cache[:primary].has_key?(index)
-
cached = node_cache[:primary][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_CFWS
-
s0 << r1
-
if r1
-
r2 = _nt_location
-
s0 << r2
-
if r2
-
r3 = _nt_CFWS
-
s0 << r3
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Primary0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:primary][start_index] = r0
-
-
r0
-
end
-
-
1
module Location0
-
1
def text_value
-
quoted_content.text_value
-
end
-
end
-
-
1
def _nt_location
-
start_index = index
-
if node_cache[:location].has_key?(index)
-
cached = node_cache[:location][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_quoted_string
-
r1.extend(Location0)
-
if r1
-
r0 = r1
-
else
-
s2, i2 = [], index
-
loop do
-
i3 = index
-
r4 = _nt_token
-
if r4
-
r3 = r4
-
else
-
if has_terminal?('\G[\\x3d]', true, index)
-
r5 = true
-
@index += 1
-
else
-
r5 = nil
-
end
-
if r5
-
r3 = r5
-
else
-
@index = i3
-
r3 = nil
-
end
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
if s2.empty?
-
@index = i2
-
r2 = nil
-
else
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
end
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:location][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class ContentLocationParser < Treetop::Runtime::CompiledParser
-
1
include ContentLocation
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module ContentTransferEncoding
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :primary
-
end
-
-
1
include RFC2822
-
-
1
include RFC2045
-
-
1
module Primary0
-
1
def CFWS1
-
elements[0]
-
end
-
-
1
def encoding
-
elements[1]
-
end
-
-
1
def CFWS2
-
elements[2]
-
end
-
-
1
def CFWS3
-
elements[4]
-
end
-
end
-
-
1
def _nt_primary
-
start_index = index
-
if node_cache[:primary].has_key?(index)
-
cached = node_cache[:primary][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_CFWS
-
s0 << r1
-
if r1
-
r2 = _nt_encoding
-
s0 << r2
-
if r2
-
r3 = _nt_CFWS
-
s0 << r3
-
if r3
-
if has_terminal?(";", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(";")
-
r5 = nil
-
end
-
if r5
-
r4 = r5
-
else
-
r4 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r4
-
if r4
-
r6 = _nt_CFWS
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Primary0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:primary][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_encoding
-
start_index = index
-
if node_cache[:encoding].has_key?(index)
-
cached = node_cache[:encoding][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
if has_terminal?("7bits", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 5))
-
@index += 5
-
else
-
terminal_parse_failure("7bits")
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
if has_terminal?("8bits", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 5))
-
@index += 5
-
else
-
terminal_parse_failure("8bits")
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?("7bit", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 4))
-
@index += 4
-
else
-
terminal_parse_failure("7bit")
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?("8bit", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 4))
-
@index += 4
-
else
-
terminal_parse_failure("8bit")
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
if has_terminal?("binary", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 6))
-
@index += 6
-
else
-
terminal_parse_failure("binary")
-
r5 = nil
-
end
-
if r5
-
r0 = r5
-
else
-
if has_terminal?("quoted-printable", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 16))
-
@index += 16
-
else
-
terminal_parse_failure("quoted-printable")
-
r6 = nil
-
end
-
if r6
-
r0 = r6
-
else
-
if has_terminal?("base64", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 6))
-
@index += 6
-
else
-
terminal_parse_failure("base64")
-
r7 = nil
-
end
-
if r7
-
r0 = r7
-
else
-
r8 = _nt_ietf_token
-
if r8
-
r0 = r8
-
else
-
r9 = _nt_custom_x_token
-
if r9
-
r0 = r9
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
-
node_cache[:encoding][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class ContentTransferEncodingParser < Treetop::Runtime::CompiledParser
-
1
include ContentTransferEncoding
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module ContentType
-
1
include Treetop::Runtime
-
-
1
def root
-
6
@root ||= :content_type
-
end
-
-
1
include RFC2822
-
-
1
include RFC2045
-
-
1
module ContentType0
-
1
def CFWS1
-
elements[0]
-
end
-
-
1
def parameter
-
2
elements[2]
-
end
-
-
1
def CFWS2
-
elements[3]
-
end
-
end
-
-
1
module ContentType1
-
1
def main_type
-
6
elements[0]
-
end
-
-
1
def sub_type
-
6
elements[2]
-
end
-
-
1
def param_hashes
-
6
elements[3]
-
end
-
end
-
-
1
module ContentType2
-
1
def parameters
-
6
param_hashes.elements.map do |param|
-
2
param.parameter.param_hash
-
end
-
end
-
end
-
-
1
def _nt_content_type
-
6
start_index = index
-
6
if node_cache[:content_type].has_key?(index)
-
cached = node_cache[:content_type][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
6
i0, s0 = index, []
-
6
r1 = _nt_main_type
-
6
s0 << r1
-
6
if r1
-
6
if has_terminal?("/", false, index)
-
6
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
6
@index += 1
-
else
-
terminal_parse_failure("/")
-
r2 = nil
-
end
-
6
s0 << r2
-
6
if r2
-
6
r3 = _nt_sub_type
-
6
s0 << r3
-
6
if r3
-
6
s4, i4 = [], index
-
6
loop do
-
8
i5, s5 = index, []
-
8
r6 = _nt_CFWS
-
8
s5 << r6
-
8
if r6
-
8
s7, i7 = [], index
-
8
loop do
-
10
if has_terminal?(";", false, index)
-
2
r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
2
@index += 1
-
else
-
8
terminal_parse_failure(";")
-
8
r8 = nil
-
end
-
10
if r8
-
2
s7 << r8
-
else
-
8
break
-
end
-
end
-
8
r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
-
8
s5 << r7
-
8
if r7
-
8
r9 = _nt_parameter
-
8
s5 << r9
-
8
if r9
-
2
r10 = _nt_CFWS
-
2
s5 << r10
-
end
-
end
-
end
-
8
if s5.last
-
2
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
2
r5.extend(ContentType0)
-
else
-
6
@index = i5
-
6
r5 = nil
-
end
-
8
if r5
-
2
s4 << r5
-
else
-
6
break
-
end
-
end
-
6
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
6
s0 << r4
-
end
-
end
-
end
-
6
if s0.last
-
6
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
6
r0.extend(ContentType1)
-
6
r0.extend(ContentType2)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
6
node_cache[:content_type][start_index] = r0
-
-
6
r0
-
end
-
-
1
def _nt_main_type
-
6
start_index = index
-
6
if node_cache[:main_type].has_key?(index)
-
cached = node_cache[:main_type][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
6
i0 = index
-
6
r1 = _nt_discrete_type
-
6
if r1
-
6
r0 = r1
-
else
-
r2 = _nt_composite_type
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
6
node_cache[:main_type][start_index] = r0
-
-
6
r0
-
end
-
-
1
module DiscreteType0
-
end
-
-
1
module DiscreteType1
-
end
-
-
1
module DiscreteType2
-
end
-
-
1
module DiscreteType3
-
end
-
-
1
module DiscreteType4
-
end
-
-
1
def _nt_discrete_type
-
6
start_index = index
-
6
if node_cache[:discrete_type].has_key?(index)
-
cached = node_cache[:discrete_type][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
6
i0 = index
-
6
i1, s1 = index, []
-
6
if has_terminal?('\G[tT]', true, index)
-
6
r2 = true
-
6
@index += 1
-
else
-
r2 = nil
-
end
-
6
s1 << r2
-
6
if r2
-
6
if has_terminal?('\G[eE]', true, index)
-
6
r3 = true
-
6
@index += 1
-
else
-
r3 = nil
-
end
-
6
s1 << r3
-
6
if r3
-
6
if has_terminal?('\G[xX]', true, index)
-
6
r4 = true
-
6
@index += 1
-
else
-
r4 = nil
-
end
-
6
s1 << r4
-
6
if r4
-
6
if has_terminal?('\G[tT]', true, index)
-
6
r5 = true
-
6
@index += 1
-
else
-
r5 = nil
-
end
-
6
s1 << r5
-
end
-
end
-
end
-
6
if s1.last
-
6
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
6
r1.extend(DiscreteType0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
6
if r1
-
6
r0 = r1
-
else
-
i6, s6 = index, []
-
if has_terminal?('\G[iI]', true, index)
-
r7 = true
-
@index += 1
-
else
-
r7 = nil
-
end
-
s6 << r7
-
if r7
-
if has_terminal?('\G[mM]', true, index)
-
r8 = true
-
@index += 1
-
else
-
r8 = nil
-
end
-
s6 << r8
-
if r8
-
if has_terminal?('\G[aA]', true, index)
-
r9 = true
-
@index += 1
-
else
-
r9 = nil
-
end
-
s6 << r9
-
if r9
-
if has_terminal?('\G[gG]', true, index)
-
r10 = true
-
@index += 1
-
else
-
r10 = nil
-
end
-
s6 << r10
-
if r10
-
if has_terminal?('\G[eE]', true, index)
-
r11 = true
-
@index += 1
-
else
-
r11 = nil
-
end
-
s6 << r11
-
end
-
end
-
end
-
end
-
if s6.last
-
r6 = instantiate_node(SyntaxNode,input, i6...index, s6)
-
r6.extend(DiscreteType1)
-
else
-
@index = i6
-
r6 = nil
-
end
-
if r6
-
r0 = r6
-
else
-
i12, s12 = index, []
-
if has_terminal?('\G[aA]', true, index)
-
r13 = true
-
@index += 1
-
else
-
r13 = nil
-
end
-
s12 << r13
-
if r13
-
if has_terminal?('\G[uU]', true, index)
-
r14 = true
-
@index += 1
-
else
-
r14 = nil
-
end
-
s12 << r14
-
if r14
-
if has_terminal?('\G[dD]', true, index)
-
r15 = true
-
@index += 1
-
else
-
r15 = nil
-
end
-
s12 << r15
-
if r15
-
if has_terminal?('\G[iI]', true, index)
-
r16 = true
-
@index += 1
-
else
-
r16 = nil
-
end
-
s12 << r16
-
if r16
-
if has_terminal?('\G[oO]', true, index)
-
r17 = true
-
@index += 1
-
else
-
r17 = nil
-
end
-
s12 << r17
-
end
-
end
-
end
-
end
-
if s12.last
-
r12 = instantiate_node(SyntaxNode,input, i12...index, s12)
-
r12.extend(DiscreteType2)
-
else
-
@index = i12
-
r12 = nil
-
end
-
if r12
-
r0 = r12
-
else
-
i18, s18 = index, []
-
if has_terminal?('\G[vV]', true, index)
-
r19 = true
-
@index += 1
-
else
-
r19 = nil
-
end
-
s18 << r19
-
if r19
-
if has_terminal?('\G[iI]', true, index)
-
r20 = true
-
@index += 1
-
else
-
r20 = nil
-
end
-
s18 << r20
-
if r20
-
if has_terminal?('\G[dD]', true, index)
-
r21 = true
-
@index += 1
-
else
-
r21 = nil
-
end
-
s18 << r21
-
if r21
-
if has_terminal?('\G[eE]', true, index)
-
r22 = true
-
@index += 1
-
else
-
r22 = nil
-
end
-
s18 << r22
-
if r22
-
if has_terminal?('\G[oO]', true, index)
-
r23 = true
-
@index += 1
-
else
-
r23 = nil
-
end
-
s18 << r23
-
end
-
end
-
end
-
end
-
if s18.last
-
r18 = instantiate_node(SyntaxNode,input, i18...index, s18)
-
r18.extend(DiscreteType3)
-
else
-
@index = i18
-
r18 = nil
-
end
-
if r18
-
r0 = r18
-
else
-
i24, s24 = index, []
-
if has_terminal?('\G[aA]', true, index)
-
r25 = true
-
@index += 1
-
else
-
r25 = nil
-
end
-
s24 << r25
-
if r25
-
if has_terminal?('\G[pP]', true, index)
-
r26 = true
-
@index += 1
-
else
-
r26 = nil
-
end
-
s24 << r26
-
if r26
-
if has_terminal?('\G[pP]', true, index)
-
r27 = true
-
@index += 1
-
else
-
r27 = nil
-
end
-
s24 << r27
-
if r27
-
if has_terminal?('\G[lL]', true, index)
-
r28 = true
-
@index += 1
-
else
-
r28 = nil
-
end
-
s24 << r28
-
if r28
-
if has_terminal?('\G[iI]', true, index)
-
r29 = true
-
@index += 1
-
else
-
r29 = nil
-
end
-
s24 << r29
-
if r29
-
if has_terminal?('\G[cC]', true, index)
-
r30 = true
-
@index += 1
-
else
-
r30 = nil
-
end
-
s24 << r30
-
if r30
-
if has_terminal?('\G[aA]', true, index)
-
r31 = true
-
@index += 1
-
else
-
r31 = nil
-
end
-
s24 << r31
-
if r31
-
if has_terminal?('\G[tT]', true, index)
-
r32 = true
-
@index += 1
-
else
-
r32 = nil
-
end
-
s24 << r32
-
if r32
-
if has_terminal?('\G[iI]', true, index)
-
r33 = true
-
@index += 1
-
else
-
r33 = nil
-
end
-
s24 << r33
-
if r33
-
if has_terminal?('\G[oO]', true, index)
-
r34 = true
-
@index += 1
-
else
-
r34 = nil
-
end
-
s24 << r34
-
if r34
-
if has_terminal?('\G[nN]', true, index)
-
r35 = true
-
@index += 1
-
else
-
r35 = nil
-
end
-
s24 << r35
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
if s24.last
-
r24 = instantiate_node(SyntaxNode,input, i24...index, s24)
-
r24.extend(DiscreteType4)
-
else
-
@index = i24
-
r24 = nil
-
end
-
if r24
-
r0 = r24
-
else
-
r36 = _nt_extension_token
-
if r36
-
r0 = r36
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
-
6
node_cache[:discrete_type][start_index] = r0
-
-
6
r0
-
end
-
-
1
module CompositeType0
-
end
-
-
1
module CompositeType1
-
end
-
-
1
def _nt_composite_type
-
start_index = index
-
if node_cache[:composite_type].has_key?(index)
-
cached = node_cache[:composite_type][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
if has_terminal?('\G[mM]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
s1 << r2
-
if r2
-
if has_terminal?('\G[eE]', true, index)
-
r3 = true
-
@index += 1
-
else
-
r3 = nil
-
end
-
s1 << r3
-
if r3
-
if has_terminal?('\G[sS]', true, index)
-
r4 = true
-
@index += 1
-
else
-
r4 = nil
-
end
-
s1 << r4
-
if r4
-
if has_terminal?('\G[sS]', true, index)
-
r5 = true
-
@index += 1
-
else
-
r5 = nil
-
end
-
s1 << r5
-
if r5
-
if has_terminal?('\G[aA]', true, index)
-
r6 = true
-
@index += 1
-
else
-
r6 = nil
-
end
-
s1 << r6
-
if r6
-
if has_terminal?('\G[gG]', true, index)
-
r7 = true
-
@index += 1
-
else
-
r7 = nil
-
end
-
s1 << r7
-
if r7
-
if has_terminal?('\G[eE]', true, index)
-
r8 = true
-
@index += 1
-
else
-
r8 = nil
-
end
-
s1 << r8
-
end
-
end
-
end
-
end
-
end
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(CompositeType0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
i9, s9 = index, []
-
if has_terminal?('\G[mM]', true, index)
-
r10 = true
-
@index += 1
-
else
-
r10 = nil
-
end
-
s9 << r10
-
if r10
-
if has_terminal?('\G[uU]', true, index)
-
r11 = true
-
@index += 1
-
else
-
r11 = nil
-
end
-
s9 << r11
-
if r11
-
if has_terminal?('\G[lL]', true, index)
-
r12 = true
-
@index += 1
-
else
-
r12 = nil
-
end
-
s9 << r12
-
if r12
-
if has_terminal?('\G[tT]', true, index)
-
r13 = true
-
@index += 1
-
else
-
r13 = nil
-
end
-
s9 << r13
-
if r13
-
if has_terminal?('\G[iI]', true, index)
-
r14 = true
-
@index += 1
-
else
-
r14 = nil
-
end
-
s9 << r14
-
if r14
-
if has_terminal?('\G[pP]', true, index)
-
r15 = true
-
@index += 1
-
else
-
r15 = nil
-
end
-
s9 << r15
-
if r15
-
if has_terminal?('\G[aA]', true, index)
-
r16 = true
-
@index += 1
-
else
-
r16 = nil
-
end
-
s9 << r16
-
if r16
-
if has_terminal?('\G[rR]', true, index)
-
r17 = true
-
@index += 1
-
else
-
r17 = nil
-
end
-
s9 << r17
-
if r17
-
if has_terminal?('\G[tT]', true, index)
-
r18 = true
-
@index += 1
-
else
-
r18 = nil
-
end
-
s9 << r18
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
if s9.last
-
r9 = instantiate_node(SyntaxNode,input, i9...index, s9)
-
r9.extend(CompositeType1)
-
else
-
@index = i9
-
r9 = nil
-
end
-
if r9
-
r0 = r9
-
else
-
r19 = _nt_extension_token
-
if r19
-
r0 = r19
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
-
node_cache[:composite_type][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_extension_token
-
6
start_index = index
-
6
if node_cache[:extension_token].has_key?(index)
-
cached = node_cache[:extension_token][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
6
i0 = index
-
6
r1 = _nt_ietf_token
-
6
if r1
-
6
r0 = r1
-
else
-
r2 = _nt_custom_x_token
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
6
node_cache[:extension_token][start_index] = r0
-
-
6
r0
-
end
-
-
1
def _nt_sub_type
-
6
start_index = index
-
6
if node_cache[:sub_type].has_key?(index)
-
cached = node_cache[:sub_type][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
6
i0 = index
-
6
r1 = _nt_extension_token
-
6
if r1
-
6
r0 = r1
-
else
-
r2 = _nt_iana_token
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
6
node_cache[:sub_type][start_index] = r0
-
-
6
r0
-
end
-
-
1
module Parameter0
-
1
def attr
-
2
elements[1]
-
end
-
-
1
def val
-
2
elements[3]
-
end
-
-
end
-
-
1
module Parameter1
-
1
def param_hash
-
2
{attr.text_value => val.text_value}
-
end
-
end
-
-
1
def _nt_parameter
-
8
start_index = index
-
8
if node_cache[:parameter].has_key?(index)
-
cached = node_cache[:parameter][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0, s0 = index, []
-
8
r2 = _nt_CFWS
-
8
if r2
-
8
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
8
s0 << r1
-
8
if r1
-
8
r3 = _nt_attribute
-
8
s0 << r3
-
8
if r3
-
2
if has_terminal?("=", false, index)
-
2
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
2
@index += 1
-
else
-
terminal_parse_failure("=")
-
r4 = nil
-
end
-
2
s0 << r4
-
2
if r4
-
2
r5 = _nt_value
-
2
s0 << r5
-
2
if r5
-
2
r7 = _nt_CFWS
-
2
if r7
-
2
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
2
s0 << r6
-
end
-
end
-
end
-
end
-
8
if s0.last
-
2
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
2
r0.extend(Parameter0)
-
2
r0.extend(Parameter1)
-
else
-
6
@index = i0
-
6
r0 = nil
-
end
-
-
8
node_cache[:parameter][start_index] = r0
-
-
8
r0
-
end
-
-
1
def _nt_attribute
-
8
start_index = index
-
8
if node_cache[:attribute].has_key?(index)
-
cached = node_cache[:attribute][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
s0, i0 = [], index
-
8
loop do
-
22
r1 = _nt_token
-
22
if r1
-
14
s0 << r1
-
else
-
8
break
-
end
-
end
-
8
if s0.empty?
-
6
@index = i0
-
6
r0 = nil
-
else
-
2
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
8
node_cache[:attribute][start_index] = r0
-
-
8
r0
-
end
-
-
1
module Value0
-
1
def text_value
-
quoted_content.text_value
-
end
-
end
-
-
1
def _nt_value
-
2
start_index = index
-
2
if node_cache[:value].has_key?(index)
-
cached = node_cache[:value][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
2
i0 = index
-
2
r1 = _nt_quoted_string
-
2
r1.extend(Value0)
-
2
if r1
-
r0 = r1
-
else
-
2
s2, i2 = [], index
-
2
loop do
-
12
i3 = index
-
12
r4 = _nt_token
-
12
if r4
-
10
r3 = r4
-
else
-
2
if has_terminal?('\G[\\x3d]', true, index)
-
r5 = true
-
@index += 1
-
else
-
2
r5 = nil
-
end
-
2
if r5
-
r3 = r5
-
else
-
2
@index = i3
-
2
r3 = nil
-
end
-
end
-
12
if r3
-
10
s2 << r3
-
else
-
2
break
-
end
-
end
-
2
if s2.empty?
-
@index = i2
-
r2 = nil
-
else
-
2
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
end
-
2
if r2
-
2
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
2
node_cache[:value][start_index] = r0
-
-
2
r0
-
end
-
-
end
-
-
1
class ContentTypeParser < Treetop::Runtime::CompiledParser
-
1
include ContentType
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module DateTime
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :primary
-
end
-
-
1
include RFC2822
-
-
1
module Primary0
-
1
def day_of_week
-
elements[0]
-
end
-
-
end
-
-
1
module Primary1
-
1
def date
-
elements[1]
-
end
-
-
1
def FWS
-
elements[2]
-
end
-
-
1
def time
-
elements[3]
-
end
-
-
end
-
-
1
def _nt_primary
-
start_index = index
-
if node_cache[:primary].has_key?(index)
-
cached = node_cache[:primary][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
i2, s2 = index, []
-
r3 = _nt_day_of_week
-
s2 << r3
-
if r3
-
if has_terminal?(",", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r4 = nil
-
end
-
s2 << r4
-
end
-
if s2.last
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
r2.extend(Primary0)
-
else
-
@index = i2
-
r2 = nil
-
end
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
r5 = _nt_date
-
s0 << r5
-
if r5
-
r6 = _nt_FWS
-
s0 << r6
-
if r6
-
r7 = _nt_time
-
s0 << r7
-
if r7
-
r9 = _nt_CFWS
-
if r9
-
r8 = r9
-
else
-
r8 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r8
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Primary1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:primary][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class DateTimeParser < Treetop::Runtime::CompiledParser
-
1
include DateTime
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module EnvelopeFrom
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :primary
-
end
-
-
1
include RFC2822
-
-
1
module Primary0
-
1
def addr_spec
-
elements[0]
-
end
-
-
1
def ctime_date
-
elements[1]
-
end
-
end
-
-
1
def _nt_primary
-
start_index = index
-
if node_cache[:primary].has_key?(index)
-
cached = node_cache[:primary][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_addr_spec
-
s0 << r1
-
if r1
-
r2 = _nt_ctime_date
-
s0 << r2
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Primary0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:primary][start_index] = r0
-
-
r0
-
end
-
-
1
module CtimeDate0
-
1
def day_name
-
elements[0]
-
end
-
-
1
def month_name
-
elements[2]
-
end
-
-
1
def day
-
elements[4]
-
end
-
-
1
def time_of_day
-
elements[6]
-
end
-
-
1
def year
-
elements[8]
-
end
-
end
-
-
1
def _nt_ctime_date
-
start_index = index
-
if node_cache[:ctime_date].has_key?(index)
-
cached = node_cache[:ctime_date][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_day_name
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
if has_terminal?(" ", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(" ")
-
r3 = nil
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
if s2.empty?
-
@index = i2
-
r2 = nil
-
else
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
end
-
s0 << r2
-
if r2
-
r4 = _nt_month_name
-
s0 << r4
-
if r4
-
s5, i5 = [], index
-
loop do
-
if has_terminal?(" ", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(" ")
-
r6 = nil
-
end
-
if r6
-
s5 << r6
-
else
-
break
-
end
-
end
-
if s5.empty?
-
@index = i5
-
r5 = nil
-
else
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
end
-
s0 << r5
-
if r5
-
r7 = _nt_day
-
s0 << r7
-
if r7
-
if has_terminal?(" ", false, index)
-
r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(" ")
-
r8 = nil
-
end
-
s0 << r8
-
if r8
-
r9 = _nt_time_of_day
-
s0 << r9
-
if r9
-
if has_terminal?(" ", false, index)
-
r10 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(" ")
-
r10 = nil
-
end
-
s0 << r10
-
if r10
-
r11 = _nt_year
-
s0 << r11
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(CtimeDate0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:ctime_date][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class EnvelopeFromParser < Treetop::Runtime::CompiledParser
-
1
include EnvelopeFrom
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module MessageIds
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :primary
-
end
-
-
1
include RFC2822
-
-
1
module Primary0
-
1
def message_ids
-
[first_msg_id] + other_msg_ids.elements.map { |o| o.msg_id_value }
-
end
-
end
-
-
1
def _nt_primary
-
start_index = index
-
if node_cache[:primary].has_key?(index)
-
cached = node_cache[:primary][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
r0 = _nt_message_ids
-
r0.extend(Primary0)
-
-
node_cache[:primary][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class MessageIdsParser < Treetop::Runtime::CompiledParser
-
1
include MessageIds
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module MimeVersion
-
1
include Treetop::Runtime
-
-
1
def root
-
4
@root ||= :version
-
end
-
-
1
include RFC2822
-
-
1
module Version0
-
1
def CFWS1
-
elements[0]
-
end
-
-
1
def major_digits
-
4
elements[1]
-
end
-
-
1
def minor_digits
-
4
elements[5]
-
end
-
-
1
def CFWS2
-
elements[6]
-
end
-
end
-
-
1
module Version1
-
1
def major
-
4
major_digits
-
end
-
-
1
def minor
-
4
minor_digits
-
end
-
end
-
-
1
def _nt_version
-
4
start_index = index
-
4
if node_cache[:version].has_key?(index)
-
cached = node_cache[:version][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
4
i0, s0 = index, []
-
4
r1 = _nt_CFWS
-
4
s0 << r1
-
4
if r1
-
4
s2, i2 = [], index
-
4
loop do
-
8
r3 = _nt_DIGIT
-
8
if r3
-
4
s2 << r3
-
else
-
4
break
-
end
-
end
-
4
if s2.empty?
-
@index = i2
-
r2 = nil
-
else
-
4
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
end
-
4
s0 << r2
-
4
if r2
-
4
r5 = _nt_comment
-
4
if r5
-
r4 = r5
-
else
-
4
r4 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
4
s0 << r4
-
4
if r4
-
4
if has_terminal?(".", false, index)
-
4
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
4
@index += 1
-
else
-
terminal_parse_failure(".")
-
r6 = nil
-
end
-
4
s0 << r6
-
4
if r6
-
4
r8 = _nt_comment
-
4
if r8
-
r7 = r8
-
else
-
4
r7 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
4
s0 << r7
-
4
if r7
-
4
s9, i9 = [], index
-
4
loop do
-
8
r10 = _nt_DIGIT
-
8
if r10
-
4
s9 << r10
-
else
-
4
break
-
end
-
end
-
4
if s9.empty?
-
@index = i9
-
r9 = nil
-
else
-
4
r9 = instantiate_node(SyntaxNode,input, i9...index, s9)
-
end
-
4
s0 << r9
-
4
if r9
-
4
r11 = _nt_CFWS
-
4
s0 << r11
-
end
-
end
-
end
-
end
-
end
-
end
-
4
if s0.last
-
4
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
4
r0.extend(Version0)
-
4
r0.extend(Version1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
4
node_cache[:version][start_index] = r0
-
-
4
r0
-
end
-
-
end
-
-
1
class MimeVersionParser < Treetop::Runtime::CompiledParser
-
1
include MimeVersion
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module PhraseLists
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :primary_phrase
-
end
-
-
1
include RFC2822
-
-
1
module PrimaryPhrase0
-
1
def phrases
-
[first_phrase] + other_phrases.elements.map { |o| o.phrase_value }
-
end
-
end
-
-
1
def _nt_primary_phrase
-
start_index = index
-
if node_cache[:primary_phrase].has_key?(index)
-
cached = node_cache[:primary_phrase][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
r0 = _nt_phrase_list
-
r0.extend(PrimaryPhrase0)
-
-
node_cache[:primary_phrase][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class PhraseListsParser < Treetop::Runtime::CompiledParser
-
1
include PhraseLists
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module Received
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :primary
-
end
-
-
1
include RFC2822
-
-
1
module Primary0
-
1
def name_val_list
-
elements[0]
-
end
-
-
1
def date_time
-
elements[2]
-
end
-
end
-
-
1
def _nt_primary
-
start_index = index
-
if node_cache[:primary].has_key?(index)
-
cached = node_cache[:primary][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_name_val_list
-
s0 << r1
-
if r1
-
if has_terminal?(";", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(";")
-
r2 = nil
-
end
-
s0 << r2
-
if r2
-
r3 = _nt_date_time
-
s0 << r3
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Primary0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:primary][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class ReceivedParser < Treetop::Runtime::CompiledParser
-
1
include Received
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module RFC2045
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :tspecials
-
end
-
-
1
def _nt_tspecials
-
start_index = index
-
if node_cache[:tspecials].has_key?(index)
-
cached = node_cache[:tspecials][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
if has_terminal?("(", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("(")
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
if has_terminal?(")", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(")")
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?("<", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("<")
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?(">", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(">")
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
if has_terminal?("@", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("@")
-
r5 = nil
-
end
-
if r5
-
r0 = r5
-
else
-
if has_terminal?(",", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r6 = nil
-
end
-
if r6
-
r0 = r6
-
else
-
if has_terminal?(";", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(";")
-
r7 = nil
-
end
-
if r7
-
r0 = r7
-
else
-
if has_terminal?(":", false, index)
-
r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r8 = nil
-
end
-
if r8
-
r0 = r8
-
else
-
if has_terminal?('\\', false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure('\\')
-
r9 = nil
-
end
-
if r9
-
r0 = r9
-
else
-
if has_terminal?("<", false, index)
-
r10 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("<")
-
r10 = nil
-
end
-
if r10
-
r0 = r10
-
else
-
if has_terminal?(">", false, index)
-
r11 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(">")
-
r11 = nil
-
end
-
if r11
-
r0 = r11
-
else
-
if has_terminal?("/", false, index)
-
r12 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("/")
-
r12 = nil
-
end
-
if r12
-
r0 = r12
-
else
-
if has_terminal?("[", false, index)
-
r13 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("[")
-
r13 = nil
-
end
-
if r13
-
r0 = r13
-
else
-
if has_terminal?("]", false, index)
-
r14 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("]")
-
r14 = nil
-
end
-
if r14
-
r0 = r14
-
else
-
if has_terminal?("?", false, index)
-
r15 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("?")
-
r15 = nil
-
end
-
if r15
-
r0 = r15
-
else
-
if has_terminal?("=", false, index)
-
r16 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("=")
-
r16 = nil
-
end
-
if r16
-
r0 = r16
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
-
node_cache[:tspecials][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_ietf_token
-
6
start_index = index
-
6
if node_cache[:ietf_token].has_key?(index)
-
cached = node_cache[:ietf_token][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
6
s0, i0 = [], index
-
6
loop do
-
36
r1 = _nt_token
-
36
if r1
-
30
s0 << r1
-
else
-
6
break
-
end
-
end
-
6
if s0.empty?
-
@index = i0
-
r0 = nil
-
else
-
6
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
6
node_cache[:ietf_token][start_index] = r0
-
-
6
r0
-
end
-
-
1
module CustomXToken0
-
end
-
-
1
def _nt_custom_x_token
-
start_index = index
-
if node_cache[:custom_x_token].has_key?(index)
-
cached = node_cache[:custom_x_token][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?('\G[xX]', true, index)
-
r1 = true
-
@index += 1
-
else
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
if has_terminal?("-", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("-")
-
r2 = nil
-
end
-
s0 << r2
-
if r2
-
s3, i3 = [], index
-
loop do
-
r4 = _nt_token
-
if r4
-
s3 << r4
-
else
-
break
-
end
-
end
-
if s3.empty?
-
@index = i3
-
r3 = nil
-
else
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
end
-
s0 << r3
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(CustomXToken0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:custom_x_token][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_iana_token
-
start_index = index
-
if node_cache[:iana_token].has_key?(index)
-
cached = node_cache[:iana_token][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
s0, i0 = [], index
-
loop do
-
r1 = _nt_token
-
if r1
-
s0 << r1
-
else
-
break
-
end
-
end
-
if s0.empty?
-
@index = i0
-
r0 = nil
-
else
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
node_cache[:iana_token][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_token
-
70
start_index = index
-
70
if node_cache[:token].has_key?(index)
-
6
cached = node_cache[:token][index]
-
6
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
6
return cached
-
end
-
-
64
i0 = index
-
64
if has_terminal?('\G[\\x21-\\x27]', true, index)
-
r1 = true
-
@index += 1
-
else
-
64
r1 = nil
-
end
-
64
if r1
-
r0 = r1
-
else
-
64
if has_terminal?('\G[\\x2a-\\x2b]', true, index)
-
r2 = true
-
@index += 1
-
else
-
64
r2 = nil
-
end
-
64
if r2
-
r0 = r2
-
else
-
64
if has_terminal?('\G[\\x2c-\\x2e]', true, index)
-
2
r3 = true
-
2
@index += 1
-
else
-
62
r3 = nil
-
end
-
64
if r3
-
2
r0 = r3
-
else
-
62
if has_terminal?('\G[\\x30-\\x39]', true, index)
-
2
r4 = true
-
2
@index += 1
-
else
-
60
r4 = nil
-
end
-
62
if r4
-
2
r0 = r4
-
else
-
60
if has_terminal?('\G[\\x41-\\x5a]', true, index)
-
6
r5 = true
-
6
@index += 1
-
else
-
54
r5 = nil
-
end
-
60
if r5
-
6
r0 = r5
-
else
-
54
if has_terminal?('\G[\\x5e-\\x7e]', true, index)
-
44
r6 = true
-
44
@index += 1
-
else
-
10
r6 = nil
-
end
-
54
if r6
-
44
r0 = r6
-
else
-
10
@index = i0
-
10
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
-
64
node_cache[:token][start_index] = r0
-
-
64
r0
-
end
-
-
end
-
-
1
class RFC2045Parser < Treetop::Runtime::CompiledParser
-
1
include RFC2045
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module RFC2822
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :ALPHA
-
end
-
-
1
include RFC2822Obsolete
-
-
1
def _nt_ALPHA
-
128
start_index = index
-
128
if node_cache[:ALPHA].has_key?(index)
-
cached = node_cache[:ALPHA][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
128
if has_terminal?('\G[a-zA-Z]', true, index)
-
104
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
104
@index += 1
-
else
-
24
r0 = nil
-
end
-
-
128
node_cache[:ALPHA][start_index] = r0
-
-
128
r0
-
end
-
-
1
def _nt_DIGIT
-
40
start_index = index
-
40
if node_cache[:DIGIT].has_key?(index)
-
cached = node_cache[:DIGIT][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
40
if has_terminal?('\G[0-9]', true, index)
-
8
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
8
@index += 1
-
else
-
32
r0 = nil
-
end
-
-
40
node_cache[:DIGIT][start_index] = r0
-
-
40
r0
-
end
-
-
1
def _nt_DQUOTE
-
66
start_index = index
-
66
if node_cache[:DQUOTE].has_key?(index)
-
16
cached = node_cache[:DQUOTE][index]
-
16
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
16
return cached
-
end
-
-
50
if has_terminal?('"', false, index)
-
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
50
terminal_parse_failure('"')
-
50
r0 = nil
-
end
-
-
50
node_cache[:DQUOTE][start_index] = r0
-
-
50
r0
-
end
-
-
1
def _nt_LF
-
start_index = index
-
if node_cache[:LF].has_key?(index)
-
cached = node_cache[:LF][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
if has_terminal?("\n", false, index)
-
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("\n")
-
r0 = nil
-
end
-
-
node_cache[:LF][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_CR
-
start_index = index
-
if node_cache[:CR].has_key?(index)
-
cached = node_cache[:CR][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
if has_terminal?("\r", false, index)
-
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("\r")
-
r0 = nil
-
end
-
-
node_cache[:CR][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_CRLF
-
142
start_index = index
-
142
if node_cache[:CRLF].has_key?(index)
-
72
cached = node_cache[:CRLF][index]
-
72
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
72
return cached
-
end
-
-
70
if has_terminal?("\r\n", false, index)
-
r0 = instantiate_node(SyntaxNode,input, index...(index + 2))
-
@index += 2
-
else
-
70
terminal_parse_failure("\r\n")
-
70
r0 = nil
-
end
-
-
70
node_cache[:CRLF][start_index] = r0
-
-
70
r0
-
end
-
-
1
def _nt_WSP
-
144
start_index = index
-
144
if node_cache[:WSP].has_key?(index)
-
74
cached = node_cache[:WSP][index]
-
74
if cached
-
2
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
2
@index = cached.interval.end
-
end
-
74
return cached
-
end
-
-
70
if has_terminal?('\G[\\x09\\x20]', true, index)
-
2
r0 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
2
@index += 1
-
else
-
68
r0 = nil
-
end
-
-
70
node_cache[:WSP][start_index] = r0
-
-
70
r0
-
end
-
-
1
module FWS0
-
1
def CRLF
-
elements[1]
-
end
-
-
end
-
-
1
module FWS1
-
1
def CRLF
-
elements[0]
-
end
-
-
end
-
-
1
def _nt_FWS
-
146
start_index = index
-
146
if node_cache[:FWS].has_key?(index)
-
76
cached = node_cache[:FWS][index]
-
76
if cached
-
2
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
2
@index = cached.interval.end
-
end
-
76
return cached
-
end
-
-
70
i0 = index
-
70
i1, s1 = index, []
-
70
s2, i2 = [], index
-
70
loop do
-
72
r3 = _nt_WSP
-
72
if r3
-
2
s2 << r3
-
else
-
70
break
-
end
-
end
-
70
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
70
s1 << r2
-
70
if r2
-
70
r4 = _nt_CRLF
-
70
s1 << r4
-
70
if r4
-
s5, i5 = [], index
-
loop do
-
r6 = _nt_WSP
-
if r6
-
s5 << r6
-
else
-
break
-
end
-
end
-
if s5.empty?
-
@index = i5
-
r5 = nil
-
else
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
end
-
s1 << r5
-
end
-
end
-
70
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(FWS0)
-
else
-
70
@index = i1
-
70
r1 = nil
-
end
-
70
if r1
-
r0 = r1
-
else
-
70
i7, s7 = index, []
-
70
r8 = _nt_CRLF
-
70
s7 << r8
-
70
if r8
-
s9, i9 = [], index
-
loop do
-
r10 = _nt_WSP
-
if r10
-
s9 << r10
-
else
-
break
-
end
-
end
-
if s9.empty?
-
@index = i9
-
r9 = nil
-
else
-
r9 = instantiate_node(SyntaxNode,input, i9...index, s9)
-
end
-
s7 << r9
-
end
-
70
if s7.last
-
r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
-
r7.extend(FWS1)
-
else
-
70
@index = i7
-
70
r7 = nil
-
end
-
70
if r7
-
r0 = r7
-
else
-
70
r11 = _nt_obs_FWS
-
70
if r11
-
2
r0 = r11
-
else
-
68
@index = i0
-
68
r0 = nil
-
end
-
end
-
end
-
-
70
node_cache[:FWS][start_index] = r0
-
-
70
r0
-
end
-
-
1
module CFWS0
-
1
def comment
-
elements[1]
-
end
-
end
-
-
1
module CFWS1
-
end
-
-
1
def _nt_CFWS
-
190
start_index = index
-
190
if node_cache[:CFWS].has_key?(index)
-
122
cached = node_cache[:CFWS][index]
-
122
if cached
-
122
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
122
@index = cached.interval.end
-
end
-
122
return cached
-
end
-
-
68
i0, s0 = index, []
-
68
s1, i1 = [], index
-
68
loop do
-
68
i2, s2 = index, []
-
68
s3, i3 = [], index
-
68
loop do
-
70
r4 = _nt_FWS
-
70
if r4
-
2
s3 << r4
-
else
-
68
break
-
end
-
end
-
68
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
68
s2 << r3
-
68
if r3
-
68
r5 = _nt_comment
-
68
s2 << r5
-
end
-
68
if s2.last
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
r2.extend(CFWS0)
-
else
-
68
@index = i2
-
68
r2 = nil
-
end
-
68
if r2
-
s1 << r2
-
else
-
68
break
-
end
-
end
-
68
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
68
s0 << r1
-
68
if r1
-
68
r7 = _nt_FWS
-
68
if r7
-
2
r6 = r7
-
else
-
66
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
68
s0 << r6
-
end
-
68
if s0.last
-
68
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
68
r0.extend(CFWS1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
68
node_cache[:CFWS][start_index] = r0
-
-
68
r0
-
end
-
-
1
def _nt_NO_WS_CTL
-
start_index = index
-
if node_cache[:NO_WS_CTL].has_key?(index)
-
cached = node_cache[:NO_WS_CTL][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
if has_terminal?('\G[\\x01-\\x08]', true, index)
-
r1 = true
-
@index += 1
-
else
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
if has_terminal?('\G[\\x0B-\\x0C]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?('\G[\\x0E-\\x1F]', true, index)
-
r3 = true
-
@index += 1
-
else
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?('\G[\\x7f]', true, index)
-
r4 = true
-
@index += 1
-
else
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
-
node_cache[:NO_WS_CTL][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_specials
-
start_index = index
-
if node_cache[:specials].has_key?(index)
-
cached = node_cache[:specials][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
if has_terminal?("(", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("(")
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
if has_terminal?(")", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(")")
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?("<", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("<")
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?(">", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(">")
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
if has_terminal?("[", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("[")
-
r5 = nil
-
end
-
if r5
-
r0 = r5
-
else
-
if has_terminal?("]", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("]")
-
r6 = nil
-
end
-
if r6
-
r0 = r6
-
else
-
if has_terminal?(":", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r7 = nil
-
end
-
if r7
-
r0 = r7
-
else
-
if has_terminal?(";", false, index)
-
r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(";")
-
r8 = nil
-
end
-
if r8
-
r0 = r8
-
else
-
if has_terminal?("@", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("@")
-
r9 = nil
-
end
-
if r9
-
r0 = r9
-
else
-
if has_terminal?('\\', false, index)
-
r10 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure('\\')
-
r10 = nil
-
end
-
if r10
-
r0 = r10
-
else
-
if has_terminal?(",", false, index)
-
r11 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r11 = nil
-
end
-
if r11
-
r0 = r11
-
else
-
if has_terminal?(".", false, index)
-
r12 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(".")
-
r12 = nil
-
end
-
if r12
-
r0 = r12
-
else
-
r13 = _nt_DQUOTE
-
if r13
-
r0 = r13
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
-
node_cache[:specials][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_ctext
-
start_index = index
-
if node_cache[:ctext].has_key?(index)
-
cached = node_cache[:ctext][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_NO_WS_CTL
-
if r1
-
r0 = r1
-
else
-
if has_terminal?('\G[\\x21-\\x27]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?('\G[\\x2a-\\x5b]', true, index)
-
r3 = true
-
@index += 1
-
else
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?('\G[\\x5d-\\x7e]', true, index)
-
r4 = true
-
@index += 1
-
else
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
-
node_cache[:ctext][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_ccontent
-
start_index = index
-
if node_cache[:ccontent].has_key?(index)
-
cached = node_cache[:ccontent][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_ctext
-
if r1
-
r0 = r1
-
else
-
r2 = _nt_quoted_pair
-
if r2
-
r0 = r2
-
else
-
r3 = _nt_comment
-
if r3
-
r0 = r3
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
-
node_cache[:ccontent][start_index] = r0
-
-
r0
-
end
-
-
1
module Comment0
-
1
def ccontent
-
elements[1]
-
end
-
end
-
-
1
module Comment1
-
end
-
-
1
def _nt_comment
-
76
start_index = index
-
76
if node_cache[:comment].has_key?(index)
-
cached = node_cache[:comment][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
76
i0, s0 = index, []
-
76
if has_terminal?("(", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
76
terminal_parse_failure("(")
-
76
r1 = nil
-
end
-
76
s0 << r1
-
76
if r1
-
s2, i2 = [], index
-
loop do
-
i3, s3 = index, []
-
r5 = _nt_FWS
-
if r5
-
r4 = r5
-
else
-
r4 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s3 << r4
-
if r4
-
r6 = _nt_ccontent
-
s3 << r6
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(Comment0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
r8 = _nt_FWS
-
if r8
-
r7 = r8
-
else
-
r7 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r7
-
if r7
-
if has_terminal?(")", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(")")
-
r9 = nil
-
end
-
s0 << r9
-
end
-
end
-
end
-
76
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Comment1)
-
else
-
76
@index = i0
-
76
r0 = nil
-
end
-
-
76
node_cache[:comment][start_index] = r0
-
-
76
r0
-
end
-
-
1
def _nt_atext
-
296
start_index = index
-
296
if node_cache[:atext].has_key?(index)
-
168
cached = node_cache[:atext][index]
-
168
if cached
-
104
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
104
@index = cached.interval.end
-
end
-
168
return cached
-
end
-
-
128
i0 = index
-
128
r1 = _nt_ALPHA
-
128
if r1
-
104
r0 = r1
-
else
-
24
r2 = _nt_DIGIT
-
24
if r2
-
r0 = r2
-
else
-
24
if has_terminal?("!", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("!")
-
24
r3 = nil
-
end
-
24
if r3
-
r0 = r3
-
else
-
24
if has_terminal?("#", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("#")
-
24
r4 = nil
-
end
-
24
if r4
-
r0 = r4
-
else
-
24
if has_terminal?("$", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("$")
-
24
r5 = nil
-
end
-
24
if r5
-
r0 = r5
-
else
-
24
if has_terminal?("%", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("%")
-
24
r6 = nil
-
end
-
24
if r6
-
r0 = r6
-
else
-
24
if has_terminal?("&", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("&")
-
24
r7 = nil
-
end
-
24
if r7
-
r0 = r7
-
else
-
24
if has_terminal?("'", false, index)
-
r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("'")
-
24
r8 = nil
-
end
-
24
if r8
-
r0 = r8
-
else
-
24
if has_terminal?("*", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("*")
-
24
r9 = nil
-
end
-
24
if r9
-
r0 = r9
-
else
-
24
if has_terminal?("+", false, index)
-
r10 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("+")
-
24
r10 = nil
-
end
-
24
if r10
-
r0 = r10
-
else
-
24
if has_terminal?("-", false, index)
-
r11 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("-")
-
24
r11 = nil
-
end
-
24
if r11
-
r0 = r11
-
else
-
24
if has_terminal?("/", false, index)
-
r12 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("/")
-
24
r12 = nil
-
end
-
24
if r12
-
r0 = r12
-
else
-
24
if has_terminal?("=", false, index)
-
r13 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("=")
-
24
r13 = nil
-
end
-
24
if r13
-
r0 = r13
-
else
-
24
if has_terminal?("?", false, index)
-
r14 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("?")
-
24
r14 = nil
-
end
-
24
if r14
-
r0 = r14
-
else
-
24
if has_terminal?("^", false, index)
-
r15 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("^")
-
24
r15 = nil
-
end
-
24
if r15
-
r0 = r15
-
else
-
24
if has_terminal?("_", false, index)
-
r16 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("_")
-
24
r16 = nil
-
end
-
24
if r16
-
r0 = r16
-
else
-
24
if has_terminal?("`", false, index)
-
r17 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("`")
-
24
r17 = nil
-
end
-
24
if r17
-
r0 = r17
-
else
-
24
if has_terminal?("{", false, index)
-
r18 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("{")
-
24
r18 = nil
-
end
-
24
if r18
-
r0 = r18
-
else
-
24
if has_terminal?("|", false, index)
-
r19 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("|")
-
24
r19 = nil
-
end
-
24
if r19
-
r0 = r19
-
else
-
24
if has_terminal?("}", false, index)
-
r20 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("}")
-
24
r20 = nil
-
end
-
24
if r20
-
r0 = r20
-
else
-
24
if has_terminal?("~", false, index)
-
r21 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
24
terminal_parse_failure("~")
-
24
r21 = nil
-
end
-
24
if r21
-
r0 = r21
-
else
-
24
@index = i0
-
24
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
-
128
node_cache[:atext][start_index] = r0
-
-
128
r0
-
end
-
-
1
def _nt_mtext
-
start_index = index
-
if node_cache[:mtext].has_key?(index)
-
cached = node_cache[:mtext][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
s0, i0 = [], index
-
loop do
-
i1 = index
-
r2 = _nt_atext
-
if r2
-
r1 = r2
-
else
-
if has_terminal?(".", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(".")
-
r3 = nil
-
end
-
if r3
-
r1 = r3
-
else
-
@index = i1
-
r1 = nil
-
end
-
end
-
if r1
-
s0 << r1
-
else
-
break
-
end
-
end
-
if s0.empty?
-
@index = i0
-
r0 = nil
-
else
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
node_cache[:mtext][start_index] = r0
-
-
r0
-
end
-
-
1
module Atom0
-
end
-
-
1
def _nt_atom
-
48
start_index = index
-
48
if node_cache[:atom].has_key?(index)
-
cached = node_cache[:atom][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
48
i0, s0 = index, []
-
48
r2 = _nt_CFWS
-
48
if r2
-
48
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
48
s0 << r1
-
48
if r1
-
48
s3, i3 = [], index
-
48
loop do
-
152
r4 = _nt_atext
-
152
if r4
-
104
s3 << r4
-
else
-
48
break
-
end
-
end
-
48
if s3.empty?
-
24
@index = i3
-
24
r3 = nil
-
else
-
24
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
end
-
48
s0 << r3
-
48
if r3
-
24
r6 = _nt_CFWS
-
24
if r6
-
24
r5 = r6
-
else
-
r5 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
24
s0 << r5
-
end
-
end
-
48
if s0.last
-
24
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
24
r0.extend(Atom0)
-
else
-
24
@index = i0
-
24
r0 = nil
-
end
-
-
48
node_cache[:atom][start_index] = r0
-
-
48
r0
-
end
-
-
1
module DotAtom0
-
1
def dot_atom_text
-
elements[1]
-
end
-
-
end
-
-
1
def _nt_dot_atom
-
8
start_index = index
-
8
if node_cache[:dot_atom].has_key?(index)
-
cached = node_cache[:dot_atom][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0, s0 = index, []
-
8
r2 = _nt_CFWS
-
8
if r2
-
8
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
8
s0 << r1
-
8
if r1
-
8
r3 = _nt_dot_atom_text
-
8
s0 << r3
-
8
if r3
-
8
r5 = _nt_CFWS
-
8
if r5
-
8
r4 = r5
-
else
-
r4 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
8
s0 << r4
-
end
-
end
-
8
if s0.last
-
8
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
8
r0.extend(DotAtom0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
8
node_cache[:dot_atom][start_index] = r0
-
-
8
r0
-
end
-
-
1
module LocalDotAtom0
-
1
def local_dot_atom_text
-
elements[1]
-
end
-
-
end
-
-
1
def _nt_local_dot_atom
-
8
start_index = index
-
8
if node_cache[:local_dot_atom].has_key?(index)
-
cached = node_cache[:local_dot_atom][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0, s0 = index, []
-
8
r2 = _nt_CFWS
-
8
if r2
-
8
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
8
s0 << r1
-
8
if r1
-
8
r3 = _nt_local_dot_atom_text
-
8
s0 << r3
-
8
if r3
-
8
r5 = _nt_CFWS
-
8
if r5
-
8
r4 = r5
-
else
-
r4 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
8
s0 << r4
-
end
-
end
-
8
if s0.last
-
8
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
8
r0.extend(LocalDotAtom0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
8
node_cache[:local_dot_atom][start_index] = r0
-
-
8
r0
-
end
-
-
1
def _nt_message_id_text
-
start_index = index
-
if node_cache[:message_id_text].has_key?(index)
-
cached = node_cache[:message_id_text][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
s0, i0 = [], index
-
loop do
-
r1 = _nt_mtext
-
if r1
-
s0 << r1
-
else
-
break
-
end
-
end
-
if s0.empty?
-
@index = i0
-
r0 = nil
-
else
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
node_cache[:message_id_text][start_index] = r0
-
-
r0
-
end
-
-
1
module DotAtomText0
-
1
def domain_text
-
elements[0]
-
end
-
-
end
-
-
1
def _nt_dot_atom_text
-
8
start_index = index
-
8
if node_cache[:dot_atom_text].has_key?(index)
-
cached = node_cache[:dot_atom_text][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
s0, i0 = [], index
-
8
loop do
-
24
i1, s1 = index, []
-
24
r2 = _nt_domain_text
-
24
s1 << r2
-
24
if r2
-
16
if has_terminal?(".", false, index)
-
8
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
8
@index += 1
-
else
-
8
terminal_parse_failure(".")
-
8
r4 = nil
-
end
-
16
if r4
-
8
r3 = r4
-
else
-
8
r3 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
16
s1 << r3
-
end
-
24
if s1.last
-
16
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
16
r1.extend(DotAtomText0)
-
else
-
8
@index = i1
-
8
r1 = nil
-
end
-
24
if r1
-
16
s0 << r1
-
else
-
8
break
-
end
-
end
-
8
if s0.empty?
-
@index = i0
-
r0 = nil
-
else
-
8
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
8
node_cache[:dot_atom_text][start_index] = r0
-
-
8
r0
-
end
-
-
1
module LocalDotAtomText0
-
1
def domain_text
-
elements[1]
-
end
-
-
end
-
-
1
def _nt_local_dot_atom_text
-
8
start_index = index
-
8
if node_cache[:local_dot_atom_text].has_key?(index)
-
cached = node_cache[:local_dot_atom_text][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
s0, i0 = [], index
-
8
loop do
-
16
i1, s1 = index, []
-
16
s2, i2 = [], index
-
16
loop do
-
16
if has_terminal?(".", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
16
terminal_parse_failure(".")
-
16
r3 = nil
-
end
-
16
if r3
-
s2 << r3
-
else
-
16
break
-
end
-
end
-
16
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
16
s1 << r2
-
16
if r2
-
16
r4 = _nt_domain_text
-
16
s1 << r4
-
16
if r4
-
8
s5, i5 = [], index
-
8
loop do
-
8
if has_terminal?(".", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
8
terminal_parse_failure(".")
-
8
r6 = nil
-
end
-
8
if r6
-
s5 << r6
-
else
-
8
break
-
end
-
end
-
8
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
8
s1 << r5
-
end
-
end
-
16
if s1.last
-
8
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
8
r1.extend(LocalDotAtomText0)
-
else
-
8
@index = i1
-
8
r1 = nil
-
end
-
16
if r1
-
8
s0 << r1
-
else
-
8
break
-
end
-
end
-
8
if s0.empty?
-
@index = i0
-
r0 = nil
-
else
-
8
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
8
node_cache[:local_dot_atom_text][start_index] = r0
-
-
8
r0
-
end
-
-
1
module DomainText0
-
1
def quoted_domain
-
elements[1]
-
end
-
end
-
-
1
module DomainText1
-
1
def DQUOTE1
-
elements[0]
-
end
-
-
1
def DQUOTE2
-
elements[3]
-
end
-
end
-
-
1
def _nt_domain_text
-
40
start_index = index
-
40
if node_cache[:domain_text].has_key?(index)
-
cached = node_cache[:domain_text][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
40
i0 = index
-
40
i1, s1 = index, []
-
40
r2 = _nt_DQUOTE
-
40
s1 << r2
-
40
if r2
-
s3, i3 = [], index
-
loop do
-
i4, s4 = index, []
-
r6 = _nt_FWS
-
if r6
-
r5 = r6
-
else
-
r5 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s4 << r5
-
if r5
-
r7 = _nt_quoted_domain
-
s4 << r7
-
end
-
if s4.last
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
r4.extend(DomainText0)
-
else
-
@index = i4
-
r4 = nil
-
end
-
if r4
-
s3 << r4
-
else
-
break
-
end
-
end
-
if s3.empty?
-
@index = i3
-
r3 = nil
-
else
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
end
-
s1 << r3
-
if r3
-
r9 = _nt_FWS
-
if r9
-
r8 = r9
-
else
-
r8 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s1 << r8
-
if r8
-
r10 = _nt_DQUOTE
-
s1 << r10
-
end
-
end
-
end
-
40
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(DomainText1)
-
else
-
40
@index = i1
-
40
r1 = nil
-
end
-
40
if r1
-
r0 = r1
-
else
-
40
s11, i11 = [], index
-
40
loop do
-
144
r12 = _nt_atext
-
144
if r12
-
104
s11 << r12
-
else
-
40
break
-
end
-
end
-
40
if s11.empty?
-
16
@index = i11
-
16
r11 = nil
-
else
-
24
r11 = instantiate_node(SyntaxNode,input, i11...index, s11)
-
end
-
40
if r11
-
24
r0 = r11
-
else
-
16
@index = i0
-
16
r0 = nil
-
end
-
end
-
-
40
node_cache[:domain_text][start_index] = r0
-
-
40
r0
-
end
-
-
1
module QuotedDomain0
-
1
def text
-
elements[1]
-
end
-
end
-
-
1
def _nt_quoted_domain
-
start_index = index
-
if node_cache[:quoted_domain].has_key?(index)
-
cached = node_cache[:quoted_domain][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_qdcontent
-
if r1
-
r0 = r1
-
else
-
i2, s2 = index, []
-
if has_terminal?("\\", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("\\")
-
r3 = nil
-
end
-
s2 << r3
-
if r3
-
r4 = _nt_text
-
s2 << r4
-
end
-
if s2.last
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
r2.extend(QuotedDomain0)
-
else
-
@index = i2
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:quoted_domain][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_qdcontent
-
start_index = index
-
if node_cache[:qdcontent].has_key?(index)
-
cached = node_cache[:qdcontent][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_NO_WS_CTL
-
if r1
-
r0 = r1
-
else
-
if has_terminal?('\G[\\x21]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?('\G[\\x23-\\x45]', true, index)
-
r3 = true
-
@index += 1
-
else
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?('\G[\\x47-\\x5b]', true, index)
-
r4 = true
-
@index += 1
-
else
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
if has_terminal?('\G[\\x5d-\\x7e]', true, index)
-
r5 = true
-
@index += 1
-
else
-
r5 = nil
-
end
-
if r5
-
r0 = r5
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
-
node_cache[:qdcontent][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_phrase
-
8
start_index = index
-
8
if node_cache[:phrase].has_key?(index)
-
cached = node_cache[:phrase][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0 = index
-
8
r1 = _nt_obs_phrase
-
8
if r1
-
8
r0 = r1
-
else
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_word
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
if s2.empty?
-
@index = i2
-
r2 = nil
-
else
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
end
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
8
node_cache[:phrase][start_index] = r0
-
-
8
r0
-
end
-
-
1
def _nt_word
-
48
start_index = index
-
48
if node_cache[:word].has_key?(index)
-
cached = node_cache[:word][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
48
i0 = index
-
48
r1 = _nt_atom
-
48
if r1
-
24
r0 = r1
-
else
-
24
r2 = _nt_quoted_string
-
24
if r2
-
r0 = r2
-
else
-
24
@index = i0
-
24
r0 = nil
-
end
-
end
-
-
48
node_cache[:word][start_index] = r0
-
-
48
r0
-
end
-
-
1
module PhraseList0
-
1
def phrase_value
-
elements[2]
-
end
-
end
-
-
1
module PhraseList1
-
1
def first_phrase
-
elements[0]
-
end
-
-
1
def other_phrases
-
elements[1]
-
end
-
end
-
-
1
def _nt_phrase_list
-
start_index = index
-
if node_cache[:phrase_list].has_key?(index)
-
cached = node_cache[:phrase_list][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_phrase
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
i3, s3 = index, []
-
if has_terminal?(",", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r4 = nil
-
end
-
s3 << r4
-
if r4
-
s5, i5 = [], index
-
loop do
-
r6 = _nt_FWS
-
if r6
-
s5 << r6
-
else
-
break
-
end
-
end
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
s3 << r5
-
if r5
-
r7 = _nt_phrase
-
s3 << r7
-
end
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(PhraseList0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(PhraseList1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:phrase_list][start_index] = r0
-
-
r0
-
end
-
-
1
module DomainLiteral0
-
1
def dcontent
-
elements[1]
-
end
-
end
-
-
1
module DomainLiteral1
-
end
-
-
1
def _nt_domain_literal
-
start_index = index
-
if node_cache[:domain_literal].has_key?(index)
-
cached = node_cache[:domain_literal][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
if has_terminal?("[", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("[")
-
r3 = nil
-
end
-
s0 << r3
-
if r3
-
s4, i4 = [], index
-
loop do
-
i5, s5 = index, []
-
r7 = _nt_FWS
-
if r7
-
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s5 << r6
-
if r6
-
r8 = _nt_dcontent
-
s5 << r8
-
end
-
if s5.last
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
r5.extend(DomainLiteral0)
-
else
-
@index = i5
-
r5 = nil
-
end
-
if r5
-
s4 << r5
-
else
-
break
-
end
-
end
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
s0 << r4
-
if r4
-
r10 = _nt_FWS
-
if r10
-
r9 = r10
-
else
-
r9 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r9
-
if r9
-
if has_terminal?("]", false, index)
-
r11 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("]")
-
r11 = nil
-
end
-
s0 << r11
-
if r11
-
r13 = _nt_CFWS
-
if r13
-
r12 = r13
-
else
-
r12 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r12
-
end
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(DomainLiteral1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:domain_literal][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_dcontent
-
start_index = index
-
if node_cache[:dcontent].has_key?(index)
-
cached = node_cache[:dcontent][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_dtext
-
if r1
-
r0 = r1
-
else
-
r2 = _nt_quoted_pair
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:dcontent][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_dtext
-
start_index = index
-
if node_cache[:dtext].has_key?(index)
-
cached = node_cache[:dtext][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_NO_WS_CTL
-
if r1
-
r0 = r1
-
else
-
if has_terminal?('\G[\\x21-\\x5a]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?('\G[\\x5e-\\x7e]', true, index)
-
r3 = true
-
@index += 1
-
else
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
-
node_cache[:dtext][start_index] = r0
-
-
r0
-
end
-
-
1
module AngleAddr0
-
1
def addr_spec
-
elements[2]
-
end
-
-
end
-
-
1
def _nt_angle_addr
-
16
start_index = index
-
16
if node_cache[:angle_addr].has_key?(index)
-
cached = node_cache[:angle_addr][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
16
i0 = index
-
16
i1, s1 = index, []
-
16
r3 = _nt_CFWS
-
16
if r3
-
16
r2 = r3
-
else
-
r2 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
16
s1 << r2
-
16
if r2
-
16
if has_terminal?("<", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
16
terminal_parse_failure("<")
-
16
r4 = nil
-
end
-
16
s1 << r4
-
16
if r4
-
r5 = _nt_addr_spec
-
s1 << r5
-
if r5
-
if has_terminal?(">", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(">")
-
r6 = nil
-
end
-
s1 << r6
-
if r6
-
r8 = _nt_CFWS
-
if r8
-
r7 = r8
-
else
-
r7 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s1 << r7
-
end
-
end
-
end
-
end
-
16
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(AngleAddr0)
-
else
-
16
@index = i1
-
16
r1 = nil
-
end
-
16
if r1
-
r0 = r1
-
else
-
16
r9 = _nt_obs_angle_addr
-
16
if r9
-
r0 = r9
-
else
-
16
@index = i0
-
16
r0 = nil
-
end
-
end
-
-
16
node_cache[:angle_addr][start_index] = r0
-
-
16
r0
-
end
-
-
1
module AddrSpec0
-
1
def local_part
-
4
elements[0]
-
end
-
-
1
def domain
-
2
elements[2]
-
end
-
end
-
-
1
def _nt_addr_spec
-
8
start_index = index
-
8
if node_cache[:addr_spec].has_key?(index)
-
cached = node_cache[:addr_spec][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0 = index
-
8
i1, s1 = index, []
-
8
r2 = _nt_local_part
-
8
s1 << r2
-
8
if r2
-
8
if has_terminal?("@", false, index)
-
8
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
8
@index += 1
-
else
-
terminal_parse_failure("@")
-
r3 = nil
-
end
-
8
s1 << r3
-
8
if r3
-
8
r4 = _nt_domain
-
8
s1 << r4
-
end
-
end
-
8
if s1.last
-
8
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
8
r1.extend(AddrSpec0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
8
if r1
-
8
r0 = r1
-
else
-
r5 = _nt_local_part
-
if r5
-
r0 = r5
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
8
node_cache[:addr_spec][start_index] = r0
-
-
8
r0
-
end
-
-
1
def _nt_local_part
-
8
start_index = index
-
8
if node_cache[:local_part].has_key?(index)
-
cached = node_cache[:local_part][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0 = index
-
8
r1 = _nt_local_dot_atom
-
8
if r1
-
8
r0 = r1
-
else
-
r2 = _nt_quoted_string
-
if r2
-
r0 = r2
-
else
-
r3 = _nt_obs_local_part
-
if r3
-
r0 = r3
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
-
8
node_cache[:local_part][start_index] = r0
-
-
8
r0
-
end
-
-
1
def _nt_domain
-
8
start_index = index
-
8
if node_cache[:domain].has_key?(index)
-
cached = node_cache[:domain][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0 = index
-
8
r1 = _nt_dot_atom
-
8
if r1
-
8
r0 = r1
-
else
-
r2 = _nt_domain_literal
-
if r2
-
r0 = r2
-
else
-
r3 = _nt_obs_domain
-
if r3
-
r0 = r3
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
-
8
node_cache[:domain][start_index] = r0
-
-
8
r0
-
end
-
-
1
module Group0
-
1
def group_name
-
elements[0]
-
end
-
-
1
def group_list
-
elements[2]
-
end
-
-
end
-
-
1
def _nt_group
-
8
start_index = index
-
8
if node_cache[:group].has_key?(index)
-
cached = node_cache[:group][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0, s0 = index, []
-
8
r1 = _nt_display_name
-
8
s0 << r1
-
8
if r1
-
8
if has_terminal?(":", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
8
terminal_parse_failure(":")
-
8
r2 = nil
-
end
-
8
s0 << r2
-
8
if r2
-
i4 = index
-
r5 = _nt_mailbox_list_group
-
if r5
-
r4 = r5
-
else
-
r6 = _nt_CFWS
-
if r6
-
r4 = r6
-
else
-
@index = i4
-
r4 = nil
-
end
-
end
-
if r4
-
r3 = r4
-
else
-
r3 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r3
-
if r3
-
if has_terminal?(";", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(";")
-
r7 = nil
-
end
-
s0 << r7
-
if r7
-
r9 = _nt_CFWS
-
if r9
-
r8 = r9
-
else
-
r8 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r8
-
end
-
end
-
end
-
end
-
8
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Group0)
-
else
-
8
@index = i0
-
8
r0 = nil
-
end
-
-
8
node_cache[:group][start_index] = r0
-
-
8
r0
-
end
-
-
1
module MailboxListGroup0
-
1
def addresses
-
[first_addr] + other_addr.elements.map { |o| o.addr_value }
-
end
-
end
-
-
1
def _nt_mailbox_list_group
-
start_index = index
-
if node_cache[:mailbox_list_group].has_key?(index)
-
cached = node_cache[:mailbox_list_group][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
r0 = _nt_mailbox_list
-
r0.extend(MailboxListGroup0)
-
-
node_cache[:mailbox_list_group][start_index] = r0
-
-
r0
-
end
-
-
1
module QuotedString0
-
1
def qcontent
-
elements[1]
-
end
-
end
-
-
1
module QuotedString1
-
1
def DQUOTE1
-
elements[1]
-
end
-
-
1
def quoted_content
-
elements[2]
-
end
-
-
1
def DQUOTE2
-
elements[4]
-
end
-
-
end
-
-
1
def _nt_quoted_string
-
26
start_index = index
-
26
if node_cache[:quoted_string].has_key?(index)
-
cached = node_cache[:quoted_string][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
26
i0, s0 = index, []
-
26
r2 = _nt_CFWS
-
26
if r2
-
26
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
26
s0 << r1
-
26
if r1
-
26
r3 = _nt_DQUOTE
-
26
s0 << r3
-
26
if r3
-
s4, i4 = [], index
-
loop do
-
i5, s5 = index, []
-
r7 = _nt_FWS
-
if r7
-
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s5 << r6
-
if r6
-
r8 = _nt_qcontent
-
s5 << r8
-
end
-
if s5.last
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
r5.extend(QuotedString0)
-
else
-
@index = i5
-
r5 = nil
-
end
-
if r5
-
s4 << r5
-
else
-
break
-
end
-
end
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
s0 << r4
-
if r4
-
r10 = _nt_FWS
-
if r10
-
r9 = r10
-
else
-
r9 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r9
-
if r9
-
r11 = _nt_DQUOTE
-
s0 << r11
-
if r11
-
r13 = _nt_CFWS
-
if r13
-
r12 = r13
-
else
-
r12 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r12
-
end
-
end
-
end
-
end
-
end
-
26
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(QuotedString1)
-
else
-
26
@index = i0
-
26
r0 = nil
-
end
-
-
26
node_cache[:quoted_string][start_index] = r0
-
-
26
r0
-
end
-
-
1
def _nt_qcontent
-
start_index = index
-
if node_cache[:qcontent].has_key?(index)
-
cached = node_cache[:qcontent][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_qtext
-
if r1
-
r0 = r1
-
else
-
r2 = _nt_quoted_pair
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:qcontent][start_index] = r0
-
-
r0
-
end
-
-
1
module QuotedPair0
-
1
def text
-
elements[1]
-
end
-
end
-
-
1
def _nt_quoted_pair
-
start_index = index
-
if node_cache[:quoted_pair].has_key?(index)
-
cached = node_cache[:quoted_pair][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
if has_terminal?("\\", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("\\")
-
r2 = nil
-
end
-
s1 << r2
-
if r2
-
r3 = _nt_text
-
s1 << r3
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(QuotedPair0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r4 = _nt_obs_qp
-
if r4
-
r0 = r4
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:quoted_pair][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_qtext
-
start_index = index
-
if node_cache[:qtext].has_key?(index)
-
cached = node_cache[:qtext][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_NO_WS_CTL
-
if r1
-
r0 = r1
-
else
-
if has_terminal?('\G[\\x21]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?('\G[\\x23-\\x5b]', true, index)
-
r3 = true
-
@index += 1
-
else
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?('\G[\\x5d-\\x7e]', true, index)
-
r4 = true
-
@index += 1
-
else
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
-
node_cache[:qtext][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_text
-
start_index = index
-
if node_cache[:text].has_key?(index)
-
cached = node_cache[:text][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
if has_terminal?('\G[\\x01-\\x09]', true, index)
-
r1 = true
-
@index += 1
-
else
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
if has_terminal?('\G[\\x0b-\\x0c]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?('\G[\\x0e-\\x7e]', true, index)
-
r3 = true
-
@index += 1
-
else
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
r4 = _nt_obs_text
-
if r4
-
r0 = r4
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
-
node_cache[:text][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_display_name
-
16
start_index = index
-
16
if node_cache[:display_name].has_key?(index)
-
8
cached = node_cache[:display_name][index]
-
8
if cached
-
8
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
8
@index = cached.interval.end
-
end
-
8
return cached
-
end
-
-
8
r0 = _nt_phrase
-
-
8
node_cache[:display_name][start_index] = r0
-
-
8
r0
-
end
-
-
1
module NameAddr0
-
1
def display_name
-
elements[0]
-
end
-
-
1
def angle_addr
-
elements[1]
-
end
-
end
-
-
1
def _nt_name_addr
-
8
start_index = index
-
8
if node_cache[:name_addr].has_key?(index)
-
cached = node_cache[:name_addr][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0 = index
-
8
i1, s1 = index, []
-
8
r2 = _nt_display_name
-
8
s1 << r2
-
8
if r2
-
8
r3 = _nt_angle_addr
-
8
s1 << r3
-
end
-
8
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(NameAddr0)
-
else
-
8
@index = i1
-
8
r1 = nil
-
end
-
8
if r1
-
r0 = r1
-
else
-
8
r4 = _nt_angle_addr
-
8
if r4
-
r0 = r4
-
else
-
8
@index = i0
-
8
r0 = nil
-
end
-
end
-
-
8
node_cache[:name_addr][start_index] = r0
-
-
8
r0
-
end
-
-
1
module MailboxList0
-
1
def addr_value
-
elements[1]
-
end
-
end
-
-
1
module MailboxList1
-
1
def first_addr
-
elements[0]
-
end
-
-
1
def other_addr
-
elements[1]
-
end
-
end
-
-
1
def _nt_mailbox_list
-
start_index = index
-
if node_cache[:mailbox_list].has_key?(index)
-
cached = node_cache[:mailbox_list][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r2 = _nt_mailbox
-
s1 << r2
-
if r2
-
s3, i3 = [], index
-
loop do
-
i4, s4 = index, []
-
i5 = index
-
if has_terminal?(",", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r6 = nil
-
end
-
if r6
-
r5 = r6
-
else
-
if has_terminal?(";", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(";")
-
r7 = nil
-
end
-
if r7
-
r5 = r7
-
else
-
@index = i5
-
r5 = nil
-
end
-
end
-
s4 << r5
-
if r5
-
r8 = _nt_mailbox
-
s4 << r8
-
end
-
if s4.last
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
r4.extend(MailboxList0)
-
else
-
@index = i4
-
r4 = nil
-
end
-
if r4
-
s3 << r4
-
else
-
break
-
end
-
end
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
s1 << r3
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(MailboxList1)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r9 = _nt_obs_mbox_list
-
if r9
-
r0 = r9
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:mailbox_list][start_index] = r0
-
-
r0
-
end
-
-
1
module Mailbox0
-
1
def dig_comments(comments, elements)
-
84
elements.each { |elem|
-
160
if elem.respond_to?(:comment)
-
comments << elem.comment
-
end
-
160
dig_comments(comments, elem.elements) if elem.elements
-
}
-
end
-
-
1
def comments
-
4
comments = []
-
4
dig_comments(comments, elements)
-
4
comments
-
end
-
end
-
-
1
def _nt_mailbox
-
8
start_index = index
-
8
if node_cache[:mailbox].has_key?(index)
-
cached = node_cache[:mailbox][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0 = index
-
8
r1 = _nt_name_addr
-
8
if r1
-
r0 = r1
-
r0.extend(Mailbox0)
-
else
-
8
r2 = _nt_addr_spec
-
8
if r2
-
8
r0 = r2
-
8
r0.extend(Mailbox0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
8
node_cache[:mailbox][start_index] = r0
-
-
8
r0
-
end
-
-
1
module Address0
-
-
1
def dig_comments(comments, elements)
-
elements.each { |elem|
-
if elem.respond_to?(:comment)
-
comments << elem.comment
-
end
-
dig_comments(comments, elem.elements) if elem.elements
-
}
-
end
-
-
1
def comments
-
comments = []
-
dig_comments(comments, elements)
-
comments
-
end
-
end
-
-
1
def _nt_address
-
8
start_index = index
-
8
if node_cache[:address].has_key?(index)
-
cached = node_cache[:address][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0 = index
-
8
r1 = _nt_group
-
8
r1.extend(Address0)
-
8
if r1
-
r0 = r1
-
else
-
8
r2 = _nt_mailbox
-
8
if r2
-
8
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
8
node_cache[:address][start_index] = r0
-
-
8
r0
-
end
-
-
1
module AddressList0
-
1
def addr_value
-
elements[3]
-
end
-
end
-
-
1
module AddressList1
-
1
def first_addr
-
8
elements[0]
-
end
-
-
1
def other_addr
-
8
elements[1]
-
end
-
end
-
-
1
def _nt_address_list
-
8
start_index = index
-
8
if node_cache[:address_list].has_key?(index)
-
cached = node_cache[:address_list][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
i0, s0 = index, []
-
8
r2 = _nt_address
-
8
if r2
-
8
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
8
s0 << r1
-
8
if r1
-
8
s3, i3 = [], index
-
8
loop do
-
8
i4, s4 = index, []
-
8
s5, i5 = [], index
-
8
loop do
-
8
r6 = _nt_FWS
-
8
if r6
-
s5 << r6
-
else
-
8
break
-
end
-
end
-
8
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
8
s4 << r5
-
8
if r5
-
8
i7 = index
-
8
if has_terminal?(",", false, index)
-
r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
8
terminal_parse_failure(",")
-
8
r8 = nil
-
end
-
8
if r8
-
r7 = r8
-
else
-
8
if has_terminal?(";", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
8
terminal_parse_failure(";")
-
8
r9 = nil
-
end
-
8
if r9
-
r7 = r9
-
else
-
8
@index = i7
-
8
r7 = nil
-
end
-
end
-
8
s4 << r7
-
8
if r7
-
s10, i10 = [], index
-
loop do
-
r11 = _nt_FWS
-
if r11
-
s10 << r11
-
else
-
break
-
end
-
end
-
r10 = instantiate_node(SyntaxNode,input, i10...index, s10)
-
s4 << r10
-
if r10
-
r13 = _nt_address
-
if r13
-
r12 = r13
-
else
-
r12 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s4 << r12
-
end
-
end
-
end
-
8
if s4.last
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
r4.extend(AddressList0)
-
else
-
8
@index = i4
-
8
r4 = nil
-
end
-
8
if r4
-
s3 << r4
-
else
-
8
break
-
end
-
end
-
8
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
8
s0 << r3
-
end
-
8
if s0.last
-
8
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
8
r0.extend(AddressList1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
8
node_cache[:address_list][start_index] = r0
-
-
8
r0
-
end
-
-
1
module DateTime0
-
1
def day_of_week
-
elements[0]
-
end
-
-
end
-
-
1
module DateTime1
-
1
def date
-
elements[1]
-
end
-
-
1
def FWS
-
elements[2]
-
end
-
-
1
def time
-
elements[3]
-
end
-
-
end
-
-
1
def _nt_date_time
-
start_index = index
-
if node_cache[:date_time].has_key?(index)
-
cached = node_cache[:date_time][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
i2, s2 = index, []
-
r3 = _nt_day_of_week
-
s2 << r3
-
if r3
-
if has_terminal?(",", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r4 = nil
-
end
-
s2 << r4
-
end
-
if s2.last
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
r2.extend(DateTime0)
-
else
-
@index = i2
-
r2 = nil
-
end
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
r5 = _nt_date
-
s0 << r5
-
if r5
-
r6 = _nt_FWS
-
s0 << r6
-
if r6
-
r7 = _nt_time
-
s0 << r7
-
if r7
-
r9 = _nt_CFWS
-
if r9
-
r8 = r9
-
else
-
r8 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r8
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(DateTime1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:date_time][start_index] = r0
-
-
r0
-
end
-
-
1
module DayOfWeek0
-
1
def day_name
-
elements[1]
-
end
-
end
-
-
1
def _nt_day_of_week
-
start_index = index
-
if node_cache[:day_of_week].has_key?(index)
-
cached = node_cache[:day_of_week][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r3 = _nt_FWS
-
if r3
-
r2 = r3
-
else
-
r2 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s1 << r2
-
if r2
-
r4 = _nt_day_name
-
s1 << r4
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(DayOfWeek0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r5 = _nt_obs_day_of_week
-
if r5
-
r0 = r5
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:day_of_week][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_day_name
-
start_index = index
-
if node_cache[:day_name].has_key?(index)
-
cached = node_cache[:day_name][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
if has_terminal?("Mon", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Mon")
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
if has_terminal?("Tue", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Tue")
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?("Wed", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Wed")
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?("Thu", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Thu")
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
if has_terminal?("Fri", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Fri")
-
r5 = nil
-
end
-
if r5
-
r0 = r5
-
else
-
if has_terminal?("Sat", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Sat")
-
r6 = nil
-
end
-
if r6
-
r0 = r6
-
else
-
if has_terminal?("Sun", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Sun")
-
r7 = nil
-
end
-
if r7
-
r0 = r7
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
-
node_cache[:day_name][start_index] = r0
-
-
r0
-
end
-
-
1
module Date0
-
1
def day
-
elements[0]
-
end
-
-
1
def month
-
elements[1]
-
end
-
-
1
def year
-
elements[2]
-
end
-
end
-
-
1
def _nt_date
-
start_index = index
-
if node_cache[:date].has_key?(index)
-
cached = node_cache[:date][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_day
-
s0 << r1
-
if r1
-
r2 = _nt_month
-
s0 << r2
-
if r2
-
r3 = _nt_year
-
s0 << r3
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Date0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:date][start_index] = r0
-
-
r0
-
end
-
-
1
module Year0
-
1
def DIGIT1
-
elements[0]
-
end
-
-
1
def DIGIT2
-
elements[1]
-
end
-
-
1
def DIGIT3
-
elements[2]
-
end
-
-
1
def DIGIT4
-
elements[3]
-
end
-
end
-
-
1
def _nt_year
-
start_index = index
-
if node_cache[:year].has_key?(index)
-
cached = node_cache[:year][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r2 = _nt_DIGIT
-
s1 << r2
-
if r2
-
r3 = _nt_DIGIT
-
s1 << r3
-
if r3
-
r4 = _nt_DIGIT
-
s1 << r4
-
if r4
-
r5 = _nt_DIGIT
-
s1 << r5
-
end
-
end
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(Year0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r6 = _nt_obs_year
-
if r6
-
r0 = r6
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:year][start_index] = r0
-
-
r0
-
end
-
-
1
module Month0
-
1
def FWS1
-
elements[0]
-
end
-
-
1
def month_name
-
elements[1]
-
end
-
-
1
def FWS2
-
elements[2]
-
end
-
end
-
-
1
def _nt_month
-
start_index = index
-
if node_cache[:month].has_key?(index)
-
cached = node_cache[:month][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r2 = _nt_FWS
-
s1 << r2
-
if r2
-
r3 = _nt_month_name
-
s1 << r3
-
if r3
-
r4 = _nt_FWS
-
s1 << r4
-
end
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(Month0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r5 = _nt_obs_month
-
if r5
-
r0 = r5
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:month][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_month_name
-
start_index = index
-
if node_cache[:month_name].has_key?(index)
-
cached = node_cache[:month_name][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
if has_terminal?("Jan", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Jan")
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
if has_terminal?("Feb", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Feb")
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?("Mar", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Mar")
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?("Apr", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Apr")
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
if has_terminal?("May", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("May")
-
r5 = nil
-
end
-
if r5
-
r0 = r5
-
else
-
if has_terminal?("Jun", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Jun")
-
r6 = nil
-
end
-
if r6
-
r0 = r6
-
else
-
if has_terminal?("Jul", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Jul")
-
r7 = nil
-
end
-
if r7
-
r0 = r7
-
else
-
if has_terminal?("Aug", false, index)
-
r8 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Aug")
-
r8 = nil
-
end
-
if r8
-
r0 = r8
-
else
-
if has_terminal?("Sep", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Sep")
-
r9 = nil
-
end
-
if r9
-
r0 = r9
-
else
-
if has_terminal?("Oct", false, index)
-
r10 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Oct")
-
r10 = nil
-
end
-
if r10
-
r0 = r10
-
else
-
if has_terminal?("Nov", false, index)
-
r11 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Nov")
-
r11 = nil
-
end
-
if r11
-
r0 = r11
-
else
-
if has_terminal?("Dec", false, index)
-
r12 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Dec")
-
r12 = nil
-
end
-
if r12
-
r0 = r12
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
-
node_cache[:month_name][start_index] = r0
-
-
r0
-
end
-
-
1
module Day0
-
1
def DIGIT
-
elements[1]
-
end
-
-
end
-
-
1
def _nt_day
-
start_index = index
-
if node_cache[:day].has_key?(index)
-
cached = node_cache[:day][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r3 = _nt_FWS
-
if r3
-
r2 = r3
-
else
-
r2 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s1 << r2
-
if r2
-
r4 = _nt_DIGIT
-
s1 << r4
-
if r4
-
r6 = _nt_DIGIT
-
if r6
-
r5 = r6
-
else
-
r5 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s1 << r5
-
end
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(Day0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r7 = _nt_obs_day
-
if r7
-
r0 = r7
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:day][start_index] = r0
-
-
r0
-
end
-
-
1
module Time0
-
1
def time_of_day
-
elements[0]
-
end
-
-
1
def FWS
-
elements[1]
-
end
-
-
1
def zone
-
elements[2]
-
end
-
end
-
-
1
def _nt_time
-
start_index = index
-
if node_cache[:time].has_key?(index)
-
cached = node_cache[:time][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_time_of_day
-
s0 << r1
-
if r1
-
r2 = _nt_FWS
-
s0 << r2
-
if r2
-
r3 = _nt_zone
-
s0 << r3
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Time0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:time][start_index] = r0
-
-
r0
-
end
-
-
1
module TimeOfDay0
-
1
def second
-
elements[1]
-
end
-
end
-
-
1
module TimeOfDay1
-
1
def hour
-
elements[0]
-
end
-
-
1
def minute
-
elements[2]
-
end
-
-
end
-
-
1
def _nt_time_of_day
-
start_index = index
-
if node_cache[:time_of_day].has_key?(index)
-
cached = node_cache[:time_of_day][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_hour
-
s0 << r1
-
if r1
-
if has_terminal?(":", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r2 = nil
-
end
-
s0 << r2
-
if r2
-
r3 = _nt_minute
-
s0 << r3
-
if r3
-
i5, s5 = index, []
-
if has_terminal?(":", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r6 = nil
-
end
-
s5 << r6
-
if r6
-
r7 = _nt_second
-
s5 << r7
-
end
-
if s5.last
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
r5.extend(TimeOfDay0)
-
else
-
@index = i5
-
r5 = nil
-
end
-
if r5
-
r4 = r5
-
else
-
r4 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r4
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(TimeOfDay1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:time_of_day][start_index] = r0
-
-
r0
-
end
-
-
1
module Hour0
-
1
def DIGIT1
-
elements[0]
-
end
-
-
1
def DIGIT2
-
elements[1]
-
end
-
end
-
-
1
def _nt_hour
-
start_index = index
-
if node_cache[:hour].has_key?(index)
-
cached = node_cache[:hour][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r2 = _nt_DIGIT
-
s1 << r2
-
if r2
-
r3 = _nt_DIGIT
-
s1 << r3
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(Hour0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r4 = _nt_obs_hour
-
if r4
-
r0 = r4
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:hour][start_index] = r0
-
-
r0
-
end
-
-
1
module Minute0
-
1
def DIGIT1
-
elements[0]
-
end
-
-
1
def DIGIT2
-
elements[1]
-
end
-
end
-
-
1
def _nt_minute
-
start_index = index
-
if node_cache[:minute].has_key?(index)
-
cached = node_cache[:minute][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r2 = _nt_DIGIT
-
s1 << r2
-
if r2
-
r3 = _nt_DIGIT
-
s1 << r3
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(Minute0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r4 = _nt_obs_minute
-
if r4
-
r0 = r4
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:minute][start_index] = r0
-
-
r0
-
end
-
-
1
module Second0
-
1
def DIGIT1
-
elements[0]
-
end
-
-
1
def DIGIT2
-
elements[1]
-
end
-
end
-
-
1
def _nt_second
-
start_index = index
-
if node_cache[:second].has_key?(index)
-
cached = node_cache[:second][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r2 = _nt_DIGIT
-
s1 << r2
-
if r2
-
r3 = _nt_DIGIT
-
s1 << r3
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(Second0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r4 = _nt_obs_second
-
if r4
-
r0 = r4
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:second][start_index] = r0
-
-
r0
-
end
-
-
1
module Zone0
-
1
def DIGIT1
-
elements[1]
-
end
-
-
1
def DIGIT2
-
elements[2]
-
end
-
-
1
def DIGIT3
-
elements[3]
-
end
-
-
1
def DIGIT4
-
elements[4]
-
end
-
end
-
-
1
def _nt_zone
-
start_index = index
-
if node_cache[:zone].has_key?(index)
-
cached = node_cache[:zone][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
i2 = index
-
if has_terminal?("+", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("+")
-
r3 = nil
-
end
-
if r3
-
r2 = r3
-
else
-
if has_terminal?("-", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("-")
-
r4 = nil
-
end
-
if r4
-
r2 = r4
-
else
-
@index = i2
-
r2 = nil
-
end
-
end
-
s1 << r2
-
if r2
-
r5 = _nt_DIGIT
-
s1 << r5
-
if r5
-
r6 = _nt_DIGIT
-
s1 << r6
-
if r6
-
r7 = _nt_DIGIT
-
s1 << r7
-
if r7
-
r8 = _nt_DIGIT
-
s1 << r8
-
end
-
end
-
end
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(Zone0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r9 = _nt_obs_zone
-
if r9
-
r0 = r9
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:zone][start_index] = r0
-
-
r0
-
end
-
-
1
module Return0
-
1
def path
-
elements[0]
-
end
-
-
1
def CRLF
-
elements[1]
-
end
-
end
-
-
1
def _nt_return
-
start_index = index
-
if node_cache[:return].has_key?(index)
-
cached = node_cache[:return][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_path
-
s0 << r1
-
if r1
-
r2 = _nt_CRLF
-
s0 << r2
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Return0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:return][start_index] = r0
-
-
r0
-
end
-
-
1
module Path0
-
end
-
-
1
def _nt_path
-
start_index = index
-
if node_cache[:path].has_key?(index)
-
cached = node_cache[:path][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r3 = _nt_CFWS
-
if r3
-
r2 = r3
-
else
-
r2 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s1 << r2
-
if r2
-
if has_terminal?("<", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("<")
-
r4 = nil
-
end
-
s1 << r4
-
if r4
-
i5 = index
-
r7 = _nt_CFWS
-
if r7
-
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
if r6
-
r5 = r6
-
else
-
r8 = _nt_addr_spec
-
if r8
-
r5 = r8
-
else
-
@index = i5
-
r5 = nil
-
end
-
end
-
s1 << r5
-
if r5
-
if has_terminal?(">", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(">")
-
r9 = nil
-
end
-
s1 << r9
-
if r9
-
r11 = _nt_CFWS
-
if r11
-
r10 = r11
-
else
-
r10 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s1 << r10
-
end
-
end
-
end
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(Path0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
r12 = _nt_obs_path
-
if r12
-
r0 = r12
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:path][start_index] = r0
-
-
r0
-
end
-
-
1
module Received0
-
1
def name_val_list
-
elements[0]
-
end
-
-
1
def date_time
-
elements[2]
-
end
-
-
1
def CRLF
-
elements[3]
-
end
-
end
-
-
1
def _nt_received
-
start_index = index
-
if node_cache[:received].has_key?(index)
-
cached = node_cache[:received][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_name_val_list
-
s0 << r1
-
if r1
-
if has_terminal?(";", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(";")
-
r2 = nil
-
end
-
s0 << r2
-
if r2
-
r3 = _nt_date_time
-
s0 << r3
-
if r3
-
r4 = _nt_CRLF
-
s0 << r4
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(Received0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:received][start_index] = r0
-
-
r0
-
end
-
-
1
module NameValList0
-
1
def CFWS
-
elements[0]
-
end
-
-
1
def name_val_pair
-
elements[1]
-
end
-
end
-
-
1
module NameValList1
-
1
def name_val_pair
-
elements[0]
-
end
-
-
end
-
-
1
module NameValList2
-
end
-
-
1
def _nt_name_val_list
-
start_index = index
-
if node_cache[:name_val_list].has_key?(index)
-
cached = node_cache[:name_val_list][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
i4, s4 = index, []
-
r5 = _nt_name_val_pair
-
s4 << r5
-
if r5
-
s6, i6 = [], index
-
loop do
-
i7, s7 = index, []
-
r8 = _nt_CFWS
-
s7 << r8
-
if r8
-
r9 = _nt_name_val_pair
-
s7 << r9
-
end
-
if s7.last
-
r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
-
r7.extend(NameValList0)
-
else
-
@index = i7
-
r7 = nil
-
end
-
if r7
-
s6 << r7
-
else
-
break
-
end
-
end
-
r6 = instantiate_node(SyntaxNode,input, i6...index, s6)
-
s4 << r6
-
end
-
if s4.last
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
r4.extend(NameValList1)
-
else
-
@index = i4
-
r4 = nil
-
end
-
if r4
-
r3 = r4
-
else
-
r3 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r3
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(NameValList2)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:name_val_list][start_index] = r0
-
-
r0
-
end
-
-
1
module NameValPair0
-
1
def item_name
-
elements[0]
-
end
-
-
1
def CFWS
-
elements[1]
-
end
-
-
1
def item_value
-
elements[2]
-
end
-
end
-
-
1
def _nt_name_val_pair
-
start_index = index
-
if node_cache[:name_val_pair].has_key?(index)
-
cached = node_cache[:name_val_pair][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_item_name
-
s0 << r1
-
if r1
-
r2 = _nt_CFWS
-
s0 << r2
-
if r2
-
r3 = _nt_item_value
-
s0 << r3
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(NameValPair0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:name_val_pair][start_index] = r0
-
-
r0
-
end
-
-
1
module ItemName0
-
end
-
-
1
module ItemName1
-
1
def ALPHA
-
elements[0]
-
end
-
-
end
-
-
1
def _nt_item_name
-
start_index = index
-
if node_cache[:item_name].has_key?(index)
-
cached = node_cache[:item_name][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_ALPHA
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
i3, s3 = index, []
-
if has_terminal?("-", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("-")
-
r5 = nil
-
end
-
if r5
-
r4 = r5
-
else
-
r4 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s3 << r4
-
if r4
-
i6 = index
-
r7 = _nt_ALPHA
-
if r7
-
r6 = r7
-
else
-
r8 = _nt_DIGIT
-
if r8
-
r6 = r8
-
else
-
@index = i6
-
r6 = nil
-
end
-
end
-
s3 << r6
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(ItemName0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ItemName1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:item_name][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_item_value
-
start_index = index
-
if node_cache[:item_value].has_key?(index)
-
cached = node_cache[:item_value][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
s1, i1 = [], index
-
loop do
-
r2 = _nt_angle_addr
-
if r2
-
s1 << r2
-
else
-
break
-
end
-
end
-
if s1.empty?
-
@index = i1
-
r1 = nil
-
else
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
end
-
if r1
-
r0 = r1
-
else
-
r3 = _nt_addr_spec
-
if r3
-
r0 = r3
-
else
-
r4 = _nt_atom
-
if r4
-
r0 = r4
-
else
-
r5 = _nt_domain
-
if r5
-
r0 = r5
-
else
-
r6 = _nt_msg_id
-
if r6
-
r0 = r6
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
-
node_cache[:item_value][start_index] = r0
-
-
r0
-
end
-
-
1
module MessageIds0
-
1
def CFWS
-
elements[0]
-
end
-
-
1
def msg_id_value
-
elements[1]
-
end
-
end
-
-
1
module MessageIds1
-
1
def first_msg_id
-
elements[0]
-
end
-
-
1
def other_msg_ids
-
elements[1]
-
end
-
end
-
-
1
def _nt_message_ids
-
start_index = index
-
if node_cache[:message_ids].has_key?(index)
-
cached = node_cache[:message_ids][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_msg_id
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
i3, s3 = index, []
-
r4 = _nt_CFWS
-
s3 << r4
-
if r4
-
r5 = _nt_msg_id
-
s3 << r5
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(MessageIds0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(MessageIds1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:message_ids][start_index] = r0
-
-
r0
-
end
-
-
1
module MsgId0
-
1
def msg_id_value
-
elements[2]
-
end
-
-
end
-
-
1
def _nt_msg_id
-
start_index = index
-
if node_cache[:msg_id].has_key?(index)
-
cached = node_cache[:msg_id][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
if has_terminal?("<", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("<")
-
r3 = nil
-
end
-
s0 << r3
-
if r3
-
r4 = _nt_msg_id_value
-
s0 << r4
-
if r4
-
if has_terminal?(">", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(">")
-
r5 = nil
-
end
-
s0 << r5
-
if r5
-
r7 = _nt_CFWS
-
if r7
-
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(MsgId0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:msg_id][start_index] = r0
-
-
r0
-
end
-
-
1
module MsgIdValue0
-
1
def id_left
-
elements[0]
-
end
-
-
1
def id_right
-
elements[2]
-
end
-
end
-
-
1
def _nt_msg_id_value
-
start_index = index
-
if node_cache[:msg_id_value].has_key?(index)
-
cached = node_cache[:msg_id_value][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_id_left
-
s0 << r1
-
if r1
-
if has_terminal?("@", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("@")
-
r2 = nil
-
end
-
s0 << r2
-
if r2
-
r3 = _nt_id_right
-
s0 << r3
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(MsgIdValue0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:msg_id_value][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_id_left
-
start_index = index
-
if node_cache[:id_left].has_key?(index)
-
cached = node_cache[:id_left][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_message_id_text
-
if r1
-
r0 = r1
-
else
-
r2 = _nt_no_fold_quote
-
if r2
-
r0 = r2
-
else
-
r3 = _nt_obs_id_left
-
if r3
-
r0 = r3
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
-
node_cache[:id_left][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_id_right
-
start_index = index
-
if node_cache[:id_right].has_key?(index)
-
cached = node_cache[:id_right][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_msg_id_dot_atom_text
-
if r1
-
r0 = r1
-
else
-
r2 = _nt_no_fold_literal
-
if r2
-
r0 = r2
-
else
-
r3 = _nt_obs_id_right
-
if r3
-
r0 = r3
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
-
node_cache[:id_right][start_index] = r0
-
-
r0
-
end
-
-
1
module MsgIdDotAtomText0
-
1
def msg_id_domain_text
-
elements[0]
-
end
-
-
end
-
-
1
def _nt_msg_id_dot_atom_text
-
start_index = index
-
if node_cache[:msg_id_dot_atom_text].has_key?(index)
-
cached = node_cache[:msg_id_dot_atom_text][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
s0, i0 = [], index
-
loop do
-
i1, s1 = index, []
-
r2 = _nt_msg_id_domain_text
-
s1 << r2
-
if r2
-
if has_terminal?(".", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(".")
-
r4 = nil
-
end
-
if r4
-
r3 = r4
-
else
-
r3 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s1 << r3
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(MsgIdDotAtomText0)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
s0 << r1
-
else
-
break
-
end
-
end
-
if s0.empty?
-
@index = i0
-
r0 = nil
-
else
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
node_cache[:msg_id_dot_atom_text][start_index] = r0
-
-
r0
-
end
-
-
1
module MsgIdDomainText0
-
1
def quoted_domain
-
elements[1]
-
end
-
end
-
-
1
module MsgIdDomainText1
-
1
def DQUOTE1
-
elements[0]
-
end
-
-
1
def DQUOTE2
-
elements[3]
-
end
-
end
-
-
1
def _nt_msg_id_domain_text
-
start_index = index
-
if node_cache[:msg_id_domain_text].has_key?(index)
-
cached = node_cache[:msg_id_domain_text][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
i1, s1 = index, []
-
r2 = _nt_DQUOTE
-
s1 << r2
-
if r2
-
s3, i3 = [], index
-
loop do
-
i4, s4 = index, []
-
r6 = _nt_FWS
-
if r6
-
r5 = r6
-
else
-
r5 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s4 << r5
-
if r5
-
r7 = _nt_quoted_domain
-
s4 << r7
-
end
-
if s4.last
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
r4.extend(MsgIdDomainText0)
-
else
-
@index = i4
-
r4 = nil
-
end
-
if r4
-
s3 << r4
-
else
-
break
-
end
-
end
-
if s3.empty?
-
@index = i3
-
r3 = nil
-
else
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
end
-
s1 << r3
-
if r3
-
r9 = _nt_FWS
-
if r9
-
r8 = r9
-
else
-
r8 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s1 << r8
-
if r8
-
r10 = _nt_DQUOTE
-
s1 << r10
-
end
-
end
-
end
-
if s1.last
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
r1.extend(MsgIdDomainText1)
-
else
-
@index = i1
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
s11, i11 = [], index
-
loop do
-
r12 = _nt_msg_id_atext
-
if r12
-
s11 << r12
-
else
-
break
-
end
-
end
-
if s11.empty?
-
@index = i11
-
r11 = nil
-
else
-
r11 = instantiate_node(SyntaxNode,input, i11...index, s11)
-
end
-
if r11
-
r0 = r11
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:msg_id_domain_text][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_msg_id_atext
-
start_index = index
-
if node_cache[:msg_id_atext].has_key?(index)
-
cached = node_cache[:msg_id_atext][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_ALPHA
-
if r1
-
r0 = r1
-
else
-
r2 = _nt_DIGIT
-
if r2
-
r0 = r2
-
else
-
if has_terminal?("!", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("!")
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?("#", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("#")
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
if has_terminal?("$", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("$")
-
r5 = nil
-
end
-
if r5
-
r0 = r5
-
else
-
if has_terminal?("%", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("%")
-
r6 = nil
-
end
-
if r6
-
r0 = r6
-
else
-
if has_terminal?("&", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("&")
-
r7 = nil
-
end
-
if r7
-
r0 = r7
-
else
-
if has_terminal?("'", false, index)
-
r8 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("'")
-
r8 = nil
-
end
-
if r8
-
r0 = r8
-
else
-
if has_terminal?("*", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("*")
-
r9 = nil
-
end
-
if r9
-
r0 = r9
-
else
-
if has_terminal?("+", false, index)
-
r10 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("+")
-
r10 = nil
-
end
-
if r10
-
r0 = r10
-
else
-
if has_terminal?("-", false, index)
-
r11 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("-")
-
r11 = nil
-
end
-
if r11
-
r0 = r11
-
else
-
if has_terminal?("/", false, index)
-
r12 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("/")
-
r12 = nil
-
end
-
if r12
-
r0 = r12
-
else
-
if has_terminal?("=", false, index)
-
r13 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("=")
-
r13 = nil
-
end
-
if r13
-
r0 = r13
-
else
-
if has_terminal?("?", false, index)
-
r14 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("?")
-
r14 = nil
-
end
-
if r14
-
r0 = r14
-
else
-
if has_terminal?("^", false, index)
-
r15 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("^")
-
r15 = nil
-
end
-
if r15
-
r0 = r15
-
else
-
if has_terminal?("_", false, index)
-
r16 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("_")
-
r16 = nil
-
end
-
if r16
-
r0 = r16
-
else
-
if has_terminal?("`", false, index)
-
r17 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("`")
-
r17 = nil
-
end
-
if r17
-
r0 = r17
-
else
-
if has_terminal?("{", false, index)
-
r18 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("{")
-
r18 = nil
-
end
-
if r18
-
r0 = r18
-
else
-
if has_terminal?("|", false, index)
-
r19 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("|")
-
r19 = nil
-
end
-
if r19
-
r0 = r19
-
else
-
if has_terminal?("}", false, index)
-
r20 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("}")
-
r20 = nil
-
end
-
if r20
-
r0 = r20
-
else
-
if has_terminal?("~", false, index)
-
r21 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("~")
-
r21 = nil
-
end
-
if r21
-
r0 = r21
-
else
-
if has_terminal?("@", false, index)
-
r22 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("@")
-
r22 = nil
-
end
-
if r22
-
r0 = r22
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
-
node_cache[:msg_id_atext][start_index] = r0
-
-
r0
-
end
-
-
1
module NoFoldQuote0
-
1
def DQUOTE1
-
elements[0]
-
end
-
-
1
def DQUOTE2
-
elements[2]
-
end
-
end
-
-
1
def _nt_no_fold_quote
-
start_index = index
-
if node_cache[:no_fold_quote].has_key?(index)
-
cached = node_cache[:no_fold_quote][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_DQUOTE
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
i3 = index
-
r4 = _nt_qtext
-
if r4
-
r3 = r4
-
else
-
r5 = _nt_quoted_pair
-
if r5
-
r3 = r5
-
else
-
@index = i3
-
r3 = nil
-
end
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
if s2.empty?
-
@index = i2
-
r2 = nil
-
else
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
end
-
s0 << r2
-
if r2
-
r6 = _nt_DQUOTE
-
s0 << r6
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(NoFoldQuote0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:no_fold_quote][start_index] = r0
-
-
r0
-
end
-
-
1
module NoFoldLiteral0
-
end
-
-
1
def _nt_no_fold_literal
-
start_index = index
-
if node_cache[:no_fold_literal].has_key?(index)
-
cached = node_cache[:no_fold_literal][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("[", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("[")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
i3 = index
-
r4 = _nt_dtext
-
if r4
-
r3 = r4
-
else
-
r5 = _nt_quoted_pair
-
if r5
-
r3 = r5
-
else
-
@index = i3
-
r3 = nil
-
end
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
if s2.empty?
-
@index = i2
-
r2 = nil
-
else
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
end
-
s0 << r2
-
if r2
-
if has_terminal?("]", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("]")
-
r6 = nil
-
end
-
s0 << r6
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(NoFoldLiteral0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:no_fold_literal][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class RFC2822Parser < Treetop::Runtime::CompiledParser
-
1
include RFC2822
-
end
-
-
end
-
# Autogenerated from a Treetop grammar. Edits may be lost.
-
-
-
1
module Mail
-
1
module RFC2822Obsolete
-
1
include Treetop::Runtime
-
-
1
def root
-
@root ||= :obs_qp
-
end
-
-
1
module ObsQp0
-
end
-
-
1
def _nt_obs_qp
-
start_index = index
-
if node_cache[:obs_qp].has_key?(index)
-
cached = node_cache[:obs_qp][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("\\", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("\\")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
if has_terminal?('\G[\\x00-\\x7F]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
s0 << r2
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsQp0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_qp][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsText0
-
1
def obs_char
-
elements[0]
-
end
-
-
end
-
-
1
module ObsText1
-
end
-
-
1
def _nt_obs_text
-
start_index = index
-
if node_cache[:obs_text].has_key?(index)
-
cached = node_cache[:obs_text][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
s1, i1 = [], index
-
loop do
-
r2 = _nt_LF
-
if r2
-
s1 << r2
-
else
-
break
-
end
-
end
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
s0 << r1
-
if r1
-
s3, i3 = [], index
-
loop do
-
r4 = _nt_CR
-
if r4
-
s3 << r4
-
else
-
break
-
end
-
end
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
s0 << r3
-
if r3
-
s5, i5 = [], index
-
loop do
-
i6, s6 = index, []
-
r7 = _nt_obs_char
-
s6 << r7
-
if r7
-
s8, i8 = [], index
-
loop do
-
r9 = _nt_LF
-
if r9
-
s8 << r9
-
else
-
break
-
end
-
end
-
r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
-
s6 << r8
-
if r8
-
s10, i10 = [], index
-
loop do
-
r11 = _nt_CR
-
if r11
-
s10 << r11
-
else
-
break
-
end
-
end
-
r10 = instantiate_node(SyntaxNode,input, i10...index, s10)
-
s6 << r10
-
end
-
end
-
if s6.last
-
r6 = instantiate_node(SyntaxNode,input, i6...index, s6)
-
r6.extend(ObsText0)
-
else
-
@index = i6
-
r6 = nil
-
end
-
if r6
-
s5 << r6
-
else
-
break
-
end
-
end
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
s0 << r5
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsText1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_text][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_obs_char
-
start_index = index
-
if node_cache[:obs_char].has_key?(index)
-
cached = node_cache[:obs_char][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
if has_terminal?('\G[\\x00-\\x09]', true, index)
-
r1 = true
-
@index += 1
-
else
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
if has_terminal?('\G[\\x0B-\\x0C]', true, index)
-
r2 = true
-
@index += 1
-
else
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?('\G[\\x0E-\\x7F]', true, index)
-
r3 = true
-
@index += 1
-
else
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
-
node_cache[:obs_char][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_obs_utext
-
start_index = index
-
if node_cache[:obs_utext].has_key?(index)
-
cached = node_cache[:obs_utext][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
r0 = _nt_obs_text
-
-
node_cache[:obs_utext][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_obs_phrase
-
8
start_index = index
-
8
if node_cache[:obs_phrase].has_key?(index)
-
cached = node_cache[:obs_phrase][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
8
s0, i0 = [], index
-
8
loop do
-
48
i1 = index
-
48
r2 = _nt_word
-
48
if r2
-
24
r1 = r2
-
else
-
24
if has_terminal?(".", false, index)
-
8
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
8
@index += 1
-
else
-
16
terminal_parse_failure(".")
-
16
r3 = nil
-
end
-
24
if r3
-
8
r1 = r3
-
else
-
16
if has_terminal?("@", false, index)
-
8
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
8
@index += 1
-
else
-
8
terminal_parse_failure("@")
-
8
r4 = nil
-
end
-
16
if r4
-
8
r1 = r4
-
else
-
8
@index = i1
-
8
r1 = nil
-
end
-
end
-
end
-
48
if r1
-
40
s0 << r1
-
else
-
8
break
-
end
-
end
-
8
if s0.empty?
-
@index = i0
-
r0 = nil
-
else
-
8
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
end
-
-
8
node_cache[:obs_phrase][start_index] = r0
-
-
8
r0
-
end
-
-
1
module ObsPhraseList0
-
end
-
-
1
module ObsPhraseList1
-
end
-
-
1
def _nt_obs_phrase_list
-
start_index = index
-
if node_cache[:obs_phrase_list].has_key?(index)
-
cached = node_cache[:obs_phrase_list][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
r1 = _nt_phrase
-
if r1
-
r0 = r1
-
else
-
i2, s2 = index, []
-
s3, i3 = [], index
-
loop do
-
i4, s4 = index, []
-
r6 = _nt_phrase
-
if r6
-
r5 = r6
-
else
-
r5 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s4 << r5
-
if r5
-
r8 = _nt_CFWS
-
if r8
-
r7 = r8
-
else
-
r7 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s4 << r7
-
if r7
-
if has_terminal?(",", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r9 = nil
-
end
-
s4 << r9
-
if r9
-
r11 = _nt_CFWS
-
if r11
-
r10 = r11
-
else
-
r10 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s4 << r10
-
end
-
end
-
end
-
if s4.last
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
r4.extend(ObsPhraseList0)
-
else
-
@index = i4
-
r4 = nil
-
end
-
if r4
-
s3 << r4
-
else
-
break
-
end
-
end
-
if s3.empty?
-
@index = i3
-
r3 = nil
-
else
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
end
-
s2 << r3
-
if r3
-
r13 = _nt_phrase
-
if r13
-
r12 = r13
-
else
-
r12 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s2 << r12
-
end
-
if s2.last
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
r2.extend(ObsPhraseList1)
-
else
-
@index = i2
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
-
node_cache[:obs_phrase_list][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsFWS0
-
1
def CRLF
-
elements[0]
-
end
-
-
end
-
-
1
module ObsFWS1
-
end
-
-
1
def _nt_obs_FWS
-
70
start_index = index
-
70
if node_cache[:obs_FWS].has_key?(index)
-
cached = node_cache[:obs_FWS][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
70
i0, s0 = index, []
-
70
s1, i1 = [], index
-
70
loop do
-
72
r2 = _nt_WSP
-
72
if r2
-
2
s1 << r2
-
else
-
70
break
-
end
-
end
-
70
if s1.empty?
-
68
@index = i1
-
68
r1 = nil
-
else
-
2
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
end
-
70
s0 << r1
-
70
if r1
-
2
s3, i3 = [], index
-
2
loop do
-
2
i4, s4 = index, []
-
2
r5 = _nt_CRLF
-
2
s4 << r5
-
2
if r5
-
s6, i6 = [], index
-
loop do
-
r7 = _nt_WSP
-
if r7
-
s6 << r7
-
else
-
break
-
end
-
end
-
if s6.empty?
-
@index = i6
-
r6 = nil
-
else
-
r6 = instantiate_node(SyntaxNode,input, i6...index, s6)
-
end
-
s4 << r6
-
end
-
2
if s4.last
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
r4.extend(ObsFWS0)
-
else
-
2
@index = i4
-
2
r4 = nil
-
end
-
2
if r4
-
s3 << r4
-
else
-
2
break
-
end
-
end
-
2
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
2
s0 << r3
-
end
-
70
if s0.last
-
2
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
2
r0.extend(ObsFWS1)
-
else
-
68
@index = i0
-
68
r0 = nil
-
end
-
-
70
node_cache[:obs_FWS][start_index] = r0
-
-
70
r0
-
end
-
-
1
module ObsDayOfWeek0
-
1
def day_name
-
elements[1]
-
end
-
-
end
-
-
1
def _nt_obs_day_of_week
-
start_index = index
-
if node_cache[:obs_day_of_week].has_key?(index)
-
cached = node_cache[:obs_day_of_week][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
r3 = _nt_day_name
-
s0 << r3
-
if r3
-
r5 = _nt_CFWS
-
if r5
-
r4 = r5
-
else
-
r4 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r4
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsDayOfWeek0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_day_of_week][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsYear0
-
1
def DIGIT1
-
elements[0]
-
end
-
-
1
def DIGIT2
-
elements[1]
-
end
-
end
-
-
1
module ObsYear1
-
end
-
-
1
def _nt_obs_year
-
start_index = index
-
if node_cache[:obs_year].has_key?(index)
-
cached = node_cache[:obs_year][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
i3, s3 = index, []
-
r4 = _nt_DIGIT
-
s3 << r4
-
if r4
-
r5 = _nt_DIGIT
-
s3 << r5
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(ObsYear0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
s0 << r3
-
if r3
-
r7 = _nt_CFWS
-
if r7
-
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r6
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsYear1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_year][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsMonth0
-
1
def CFWS1
-
elements[0]
-
end
-
-
1
def month_name
-
elements[1]
-
end
-
-
1
def CFWS2
-
elements[2]
-
end
-
end
-
-
1
def _nt_obs_month
-
start_index = index
-
if node_cache[:obs_month].has_key?(index)
-
cached = node_cache[:obs_month][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_CFWS
-
s0 << r1
-
if r1
-
r2 = _nt_month_name
-
s0 << r2
-
if r2
-
r3 = _nt_CFWS
-
s0 << r3
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsMonth0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_month][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsDay0
-
1
def DIGIT1
-
elements[0]
-
end
-
-
1
def DIGIT2
-
elements[1]
-
end
-
end
-
-
1
module ObsDay1
-
end
-
-
1
def _nt_obs_day
-
start_index = index
-
if node_cache[:obs_day].has_key?(index)
-
cached = node_cache[:obs_day][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
i3 = index
-
r4 = _nt_DIGIT
-
if r4
-
r3 = r4
-
else
-
i5, s5 = index, []
-
r6 = _nt_DIGIT
-
s5 << r6
-
if r6
-
r7 = _nt_DIGIT
-
s5 << r7
-
end
-
if s5.last
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
r5.extend(ObsDay0)
-
else
-
@index = i5
-
r5 = nil
-
end
-
if r5
-
r3 = r5
-
else
-
@index = i3
-
r3 = nil
-
end
-
end
-
s0 << r3
-
if r3
-
r9 = _nt_CFWS
-
if r9
-
r8 = r9
-
else
-
r8 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r8
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsDay1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_day][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsHour0
-
1
def DIGIT1
-
elements[0]
-
end
-
-
1
def DIGIT2
-
elements[1]
-
end
-
end
-
-
1
module ObsHour1
-
end
-
-
1
def _nt_obs_hour
-
start_index = index
-
if node_cache[:obs_hour].has_key?(index)
-
cached = node_cache[:obs_hour][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
i3, s3 = index, []
-
r4 = _nt_DIGIT
-
s3 << r4
-
if r4
-
r5 = _nt_DIGIT
-
s3 << r5
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(ObsHour0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
s0 << r3
-
if r3
-
r7 = _nt_CFWS
-
if r7
-
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r6
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsHour1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_hour][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsMinute0
-
1
def DIGIT1
-
elements[0]
-
end
-
-
1
def DIGIT2
-
elements[1]
-
end
-
end
-
-
1
module ObsMinute1
-
end
-
-
1
def _nt_obs_minute
-
start_index = index
-
if node_cache[:obs_minute].has_key?(index)
-
cached = node_cache[:obs_minute][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
i3, s3 = index, []
-
r4 = _nt_DIGIT
-
s3 << r4
-
if r4
-
r5 = _nt_DIGIT
-
s3 << r5
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(ObsMinute0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
s0 << r3
-
if r3
-
r7 = _nt_CFWS
-
if r7
-
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r6
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsMinute1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_minute][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsSecond0
-
1
def DIGIT1
-
elements[0]
-
end
-
-
1
def DIGIT2
-
elements[1]
-
end
-
end
-
-
1
module ObsSecond1
-
end
-
-
1
def _nt_obs_second
-
start_index = index
-
if node_cache[:obs_second].has_key?(index)
-
cached = node_cache[:obs_second][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
i3, s3 = index, []
-
r4 = _nt_DIGIT
-
s3 << r4
-
if r4
-
r5 = _nt_DIGIT
-
s3 << r5
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(ObsSecond0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
s0 << r3
-
if r3
-
r7 = _nt_CFWS
-
if r7
-
r6 = r7
-
else
-
r6 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r6
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsSecond1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_second][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_obs_zone
-
start_index = index
-
if node_cache[:obs_zone].has_key?(index)
-
cached = node_cache[:obs_zone][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0 = index
-
if has_terminal?("UT", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
-
@index += 2
-
else
-
terminal_parse_failure("UT")
-
r1 = nil
-
end
-
if r1
-
r0 = r1
-
else
-
if has_terminal?("GMT", false, index)
-
r2 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("GMT")
-
r2 = nil
-
end
-
if r2
-
r0 = r2
-
else
-
if has_terminal?("EST", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("EST")
-
r3 = nil
-
end
-
if r3
-
r0 = r3
-
else
-
if has_terminal?("EDT", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("EDT")
-
r4 = nil
-
end
-
if r4
-
r0 = r4
-
else
-
if has_terminal?("CST", false, index)
-
r5 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("CST")
-
r5 = nil
-
end
-
if r5
-
r0 = r5
-
else
-
if has_terminal?("CDT", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("CDT")
-
r6 = nil
-
end
-
if r6
-
r0 = r6
-
else
-
if has_terminal?("MST", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("MST")
-
r7 = nil
-
end
-
if r7
-
r0 = r7
-
else
-
if has_terminal?("MDT", false, index)
-
r8 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("MDT")
-
r8 = nil
-
end
-
if r8
-
r0 = r8
-
else
-
if has_terminal?("PST", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("PST")
-
r9 = nil
-
end
-
if r9
-
r0 = r9
-
else
-
if has_terminal?("PDT", false, index)
-
r10 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("PDT")
-
r10 = nil
-
end
-
if r10
-
r0 = r10
-
else
-
if has_terminal?('\G[\\x41-\\x49]', true, index)
-
r11 = true
-
@index += 1
-
else
-
r11 = nil
-
end
-
if r11
-
r0 = r11
-
else
-
if has_terminal?('\G[\\x4B-\\x5A]', true, index)
-
r12 = true
-
@index += 1
-
else
-
r12 = nil
-
end
-
if r12
-
r0 = r12
-
else
-
if has_terminal?('\G[\\x61-\\x69]', true, index)
-
r13 = true
-
@index += 1
-
else
-
r13 = nil
-
end
-
if r13
-
r0 = r13
-
else
-
if has_terminal?('\G[\\x6B-\\x7A]', true, index)
-
r14 = true
-
@index += 1
-
else
-
r14 = nil
-
end
-
if r14
-
r0 = r14
-
else
-
@index = i0
-
r0 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
-
node_cache[:obs_zone][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsAngleAddr0
-
1
def addr_spec
-
elements[3]
-
end
-
-
end
-
-
1
def _nt_obs_angle_addr
-
16
start_index = index
-
16
if node_cache[:obs_angle_addr].has_key?(index)
-
cached = node_cache[:obs_angle_addr][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
16
i0, s0 = index, []
-
16
r2 = _nt_CFWS
-
16
if r2
-
16
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
16
s0 << r1
-
16
if r1
-
16
if has_terminal?("<", false, index)
-
r3 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
16
terminal_parse_failure("<")
-
16
r3 = nil
-
end
-
16
s0 << r3
-
16
if r3
-
r5 = _nt_obs_route
-
if r5
-
r4 = r5
-
else
-
r4 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r4
-
if r4
-
r6 = _nt_addr_spec
-
s0 << r6
-
if r6
-
if has_terminal?(">", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(">")
-
r7 = nil
-
end
-
s0 << r7
-
if r7
-
r9 = _nt_CFWS
-
if r9
-
r8 = r9
-
else
-
r8 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r8
-
end
-
end
-
end
-
end
-
end
-
16
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsAngleAddr0)
-
else
-
16
@index = i0
-
16
r0 = nil
-
end
-
-
16
node_cache[:obs_angle_addr][start_index] = r0
-
-
16
r0
-
end
-
-
1
module ObsRoute0
-
1
def obs_domain_list
-
elements[1]
-
end
-
-
end
-
-
1
def _nt_obs_route
-
start_index = index
-
if node_cache[:obs_route].has_key?(index)
-
cached = node_cache[:obs_route][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r2 = _nt_CFWS
-
if r2
-
r1 = r2
-
else
-
r1 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r1
-
if r1
-
r3 = _nt_obs_domain_list
-
s0 << r3
-
if r3
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r6 = _nt_CFWS
-
if r6
-
r5 = r6
-
else
-
r5 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r5
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsRoute0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_route][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsDomainList0
-
1
def domain
-
elements[3]
-
end
-
end
-
-
1
module ObsDomainList1
-
1
def domain
-
elements[1]
-
end
-
-
end
-
-
1
def _nt_obs_domain_list
-
start_index = index
-
if node_cache[:obs_domain_list].has_key?(index)
-
cached = node_cache[:obs_domain_list][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("@", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("@")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
r2 = _nt_domain
-
s0 << r2
-
if r2
-
s3, i3 = [], index
-
loop do
-
i4, s4 = index, []
-
s5, i5 = [], index
-
loop do
-
if has_terminal?(",", false, index)
-
r6 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r6 = nil
-
end
-
if r6
-
s5 << r6
-
else
-
break
-
end
-
end
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
s4 << r5
-
if r5
-
r8 = _nt_CFWS
-
if r8
-
r7 = r8
-
else
-
r7 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s4 << r7
-
if r7
-
if has_terminal?("@", false, index)
-
r9 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure("@")
-
r9 = nil
-
end
-
s4 << r9
-
if r9
-
r10 = _nt_domain
-
s4 << r10
-
end
-
end
-
end
-
if s4.last
-
r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
-
r4.extend(ObsDomainList0)
-
else
-
@index = i4
-
r4 = nil
-
end
-
if r4
-
s3 << r4
-
else
-
break
-
end
-
end
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
s0 << r3
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsDomainList1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_domain_list][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsLocalPart0
-
1
def word
-
elements[1]
-
end
-
end
-
-
1
module ObsLocalPart1
-
1
def word
-
elements[0]
-
end
-
-
end
-
-
1
def _nt_obs_local_part
-
start_index = index
-
if node_cache[:obs_local_part].has_key?(index)
-
cached = node_cache[:obs_local_part][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_word
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
i3, s3 = index, []
-
if has_terminal?(".", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(".")
-
r4 = nil
-
end
-
s3 << r4
-
if r4
-
r5 = _nt_word
-
s3 << r5
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(ObsLocalPart0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsLocalPart1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_local_part][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsDomain0
-
1
def atom
-
elements[1]
-
end
-
end
-
-
1
module ObsDomain1
-
1
def atom
-
elements[0]
-
end
-
-
end
-
-
1
def _nt_obs_domain
-
start_index = index
-
if node_cache[:obs_domain].has_key?(index)
-
cached = node_cache[:obs_domain][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_atom
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
i3, s3 = index, []
-
if has_terminal?(".", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(".")
-
r4 = nil
-
end
-
s3 << r4
-
if r4
-
r5 = _nt_atom
-
s3 << r5
-
end
-
if s3.last
-
r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
-
r3.extend(ObsDomain0)
-
else
-
@index = i3
-
r3 = nil
-
end
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsDomain1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_domain][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsMboxList0
-
end
-
-
1
module ObsMboxList1
-
end
-
-
1
def _nt_obs_mbox_list
-
start_index = index
-
if node_cache[:obs_mbox_list].has_key?(index)
-
cached = node_cache[:obs_mbox_list][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
s1, i1 = [], index
-
loop do
-
i2, s2 = index, []
-
r4 = _nt_mailbox
-
if r4
-
r3 = r4
-
else
-
r3 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s2 << r3
-
if r3
-
r6 = _nt_CFWS
-
if r6
-
r5 = r6
-
else
-
r5 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s2 << r5
-
if r5
-
if has_terminal?(",", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r7 = nil
-
end
-
s2 << r7
-
if r7
-
r9 = _nt_CFWS
-
if r9
-
r8 = r9
-
else
-
r8 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s2 << r8
-
end
-
end
-
end
-
if s2.last
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
r2.extend(ObsMboxList0)
-
else
-
@index = i2
-
r2 = nil
-
end
-
if r2
-
s1 << r2
-
else
-
break
-
end
-
end
-
if s1.empty?
-
@index = i1
-
r1 = nil
-
else
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
end
-
s0 << r1
-
if r1
-
r11 = _nt_mailbox
-
if r11
-
r10 = r11
-
else
-
r10 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r10
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsMboxList1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_mbox_list][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsAddrList0
-
end
-
-
1
module ObsAddrList1
-
end
-
-
1
def _nt_obs_addr_list
-
start_index = index
-
if node_cache[:obs_addr_list].has_key?(index)
-
cached = node_cache[:obs_addr_list][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
s1, i1 = [], index
-
loop do
-
i2, s2 = index, []
-
r4 = _nt_address
-
if r4
-
r3 = r4
-
else
-
r3 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s2 << r3
-
if r3
-
r6 = _nt_CFWS
-
if r6
-
r5 = r6
-
else
-
r5 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s2 << r5
-
if r5
-
if has_terminal?(",", false, index)
-
r7 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(",")
-
r7 = nil
-
end
-
s2 << r7
-
if r7
-
r9 = _nt_CFWS
-
if r9
-
r8 = r9
-
else
-
r8 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s2 << r8
-
end
-
end
-
end
-
if s2.last
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
r2.extend(ObsAddrList0)
-
else
-
@index = i2
-
r2 = nil
-
end
-
if r2
-
s1 << r2
-
else
-
break
-
end
-
end
-
if s1.empty?
-
@index = i1
-
r1 = nil
-
else
-
r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
-
end
-
s0 << r1
-
if r1
-
r11 = _nt_address
-
if r11
-
r10 = r11
-
else
-
r10 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
s0 << r10
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsAddrList1)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_addr_list][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_obs_fields
-
start_index = index
-
if node_cache[:obs_fields].has_key?(index)
-
cached = node_cache[:obs_fields][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
s0, i0 = [], index
-
loop do
-
i1 = index
-
r2 = _nt_obs_return
-
if r2
-
r1 = r2
-
else
-
r3 = _nt_obs_received
-
if r3
-
r1 = r3
-
else
-
r4 = _nt_obs_orig_date
-
if r4
-
r1 = r4
-
else
-
r5 = _nt_obs_from
-
if r5
-
r1 = r5
-
else
-
r6 = _nt_obs_sender
-
if r6
-
r1 = r6
-
else
-
r7 = _nt_obs_reply_to
-
if r7
-
r1 = r7
-
else
-
r8 = _nt_obs_to
-
if r8
-
r1 = r8
-
else
-
r9 = _nt_obs_cc
-
if r9
-
r1 = r9
-
else
-
r10 = _nt_obs_bcc
-
if r10
-
r1 = r10
-
else
-
r11 = _nt_obs_message_id
-
if r11
-
r1 = r11
-
else
-
r12 = _nt_obs_in_reply_to
-
if r12
-
r1 = r12
-
else
-
r13 = _nt_obs_references
-
if r13
-
r1 = r13
-
else
-
r14 = _nt_obs_subject
-
if r14
-
r1 = r14
-
else
-
r15 = _nt_obs_comments
-
if r15
-
r1 = r15
-
else
-
r16 = _nt_obs_keywords
-
if r16
-
r1 = r16
-
else
-
r17 = _nt_obs_resent_date
-
if r17
-
r1 = r17
-
else
-
r18 = _nt_obs_resent_from
-
if r18
-
r1 = r18
-
else
-
r19 = _nt_obs_resent_send
-
if r19
-
r1 = r19
-
else
-
r20 = _nt_obs_resent_rply
-
if r20
-
r1 = r20
-
else
-
r21 = _nt_obs_resent_to
-
if r21
-
r1 = r21
-
else
-
r22 = _nt_obs_resent_cc
-
if r22
-
r1 = r22
-
else
-
r23 = _nt_obs_resent_bcc
-
if r23
-
r1 = r23
-
else
-
r24 = _nt_obs_resent_mid
-
if r24
-
r1 = r24
-
else
-
r25 = _nt_obs_optional
-
if r25
-
r1 = r25
-
else
-
@index = i1
-
r1 = nil
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
if r1
-
s0 << r1
-
else
-
break
-
end
-
end
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
-
node_cache[:obs_fields][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsOrigDate0
-
1
def date_time
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_orig_date
-
start_index = index
-
if node_cache[:obs_orig_date].has_key?(index)
-
cached = node_cache[:obs_orig_date][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Date", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 4))
-
@index += 4
-
else
-
terminal_parse_failure("Date")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_date_time
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsOrigDate0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_orig_date][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsFrom0
-
1
def mailbox_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_from
-
start_index = index
-
if node_cache[:obs_from].has_key?(index)
-
cached = node_cache[:obs_from][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("From", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 4))
-
@index += 4
-
else
-
terminal_parse_failure("From")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_mailbox_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsFrom0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_from][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsSender0
-
1
def mailbox
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_sender
-
start_index = index
-
if node_cache[:obs_sender].has_key?(index)
-
cached = node_cache[:obs_sender][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Sender", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 6))
-
@index += 6
-
else
-
terminal_parse_failure("Sender")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_mailbox
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsSender0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_sender][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsReplyTo0
-
1
def mailbox_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_reply_to
-
start_index = index
-
if node_cache[:obs_reply_to].has_key?(index)
-
cached = node_cache[:obs_reply_to][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Reply-To", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 8))
-
@index += 8
-
else
-
terminal_parse_failure("Reply-To")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_mailbox_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsReplyTo0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_reply_to][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsTo0
-
1
def address_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_to
-
start_index = index
-
if node_cache[:obs_to].has_key?(index)
-
cached = node_cache[:obs_to][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("To", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
-
@index += 2
-
else
-
terminal_parse_failure("To")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_address_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsTo0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_to][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsCc0
-
1
def address_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_cc
-
start_index = index
-
if node_cache[:obs_cc].has_key?(index)
-
cached = node_cache[:obs_cc][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Cc", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 2))
-
@index += 2
-
else
-
terminal_parse_failure("Cc")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_address_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsCc0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_cc][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsBcc0
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_bcc
-
start_index = index
-
if node_cache[:obs_bcc].has_key?(index)
-
cached = node_cache[:obs_bcc][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Bcc", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 3))
-
@index += 3
-
else
-
terminal_parse_failure("Bcc")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
i5 = index
-
r6 = _nt_address_list
-
if r6
-
r5 = r6
-
else
-
r8 = _nt_CFWS
-
if r8
-
r7 = r8
-
else
-
r7 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
if r7
-
r5 = r7
-
else
-
@index = i5
-
r5 = nil
-
end
-
end
-
s0 << r5
-
if r5
-
r9 = _nt_CRLF
-
s0 << r9
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsBcc0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_bcc][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsMessageId0
-
1
def msg_id
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_message_id
-
start_index = index
-
if node_cache[:obs_message_id].has_key?(index)
-
cached = node_cache[:obs_message_id][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Message-ID", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 10))
-
@index += 10
-
else
-
terminal_parse_failure("Message-ID")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_msg_id
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsMessageId0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_message_id][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsInReplyTo0
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_in_reply_to
-
start_index = index
-
if node_cache[:obs_in_reply_to].has_key?(index)
-
cached = node_cache[:obs_in_reply_to][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("In-Reply-To", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 11))
-
@index += 11
-
else
-
terminal_parse_failure("In-Reply-To")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
s5, i5 = [], index
-
loop do
-
i6 = index
-
r7 = _nt_phrase
-
if r7
-
r6 = r7
-
else
-
r8 = _nt_msg_id
-
if r8
-
r6 = r8
-
else
-
@index = i6
-
r6 = nil
-
end
-
end
-
if r6
-
s5 << r6
-
else
-
break
-
end
-
end
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
s0 << r5
-
if r5
-
r9 = _nt_CRLF
-
s0 << r9
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsInReplyTo0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_in_reply_to][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsReferences0
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_references
-
start_index = index
-
if node_cache[:obs_references].has_key?(index)
-
cached = node_cache[:obs_references][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("References", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 10))
-
@index += 10
-
else
-
terminal_parse_failure("References")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
s5, i5 = [], index
-
loop do
-
i6 = index
-
r7 = _nt_phrase
-
if r7
-
r6 = r7
-
else
-
r8 = _nt_msg_id
-
if r8
-
r6 = r8
-
else
-
@index = i6
-
r6 = nil
-
end
-
end
-
if r6
-
s5 << r6
-
else
-
break
-
end
-
end
-
r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
-
s0 << r5
-
if r5
-
r9 = _nt_CRLF
-
s0 << r9
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsReferences0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_references][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_obs_id_left
-
start_index = index
-
if node_cache[:obs_id_left].has_key?(index)
-
cached = node_cache[:obs_id_left][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
r0 = _nt_local_part
-
-
node_cache[:obs_id_left][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_obs_id_right
-
start_index = index
-
if node_cache[:obs_id_right].has_key?(index)
-
cached = node_cache[:obs_id_right][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
r0 = _nt_domain
-
-
node_cache[:obs_id_right][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsSubject0
-
1
def unstructured
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_subject
-
start_index = index
-
if node_cache[:obs_subject].has_key?(index)
-
cached = node_cache[:obs_subject][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Subject", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 7))
-
@index += 7
-
else
-
terminal_parse_failure("Subject")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_unstructured
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsSubject0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_subject][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsComments0
-
1
def unstructured
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_comments
-
start_index = index
-
if node_cache[:obs_comments].has_key?(index)
-
cached = node_cache[:obs_comments][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Comments", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 8))
-
@index += 8
-
else
-
terminal_parse_failure("Comments")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_unstructured
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsComments0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_comments][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsKeywords0
-
1
def obs_phrase_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_keywords
-
start_index = index
-
if node_cache[:obs_keywords].has_key?(index)
-
cached = node_cache[:obs_keywords][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Keywords", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 8))
-
@index += 8
-
else
-
terminal_parse_failure("Keywords")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_obs_phrase_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsKeywords0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_keywords][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsResentFrom0
-
1
def mailbox_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_resent_from
-
start_index = index
-
if node_cache[:obs_resent_from].has_key?(index)
-
cached = node_cache[:obs_resent_from][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Resent-From", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 11))
-
@index += 11
-
else
-
terminal_parse_failure("Resent-From")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_mailbox_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsResentFrom0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_resent_from][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsResentSend0
-
1
def mailbox
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_resent_send
-
start_index = index
-
if node_cache[:obs_resent_send].has_key?(index)
-
cached = node_cache[:obs_resent_send][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Resent-Sender", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 13))
-
@index += 13
-
else
-
terminal_parse_failure("Resent-Sender")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_mailbox
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsResentSend0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_resent_send][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsResentDate0
-
1
def date_time
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_resent_date
-
start_index = index
-
if node_cache[:obs_resent_date].has_key?(index)
-
cached = node_cache[:obs_resent_date][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Resent-Date", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 11))
-
@index += 11
-
else
-
terminal_parse_failure("Resent-Date")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_date_time
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsResentDate0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_resent_date][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsResentTo0
-
1
def address_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_resent_to
-
start_index = index
-
if node_cache[:obs_resent_to].has_key?(index)
-
cached = node_cache[:obs_resent_to][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Resent-To", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 9))
-
@index += 9
-
else
-
terminal_parse_failure("Resent-To")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_address_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsResentTo0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_resent_to][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsResentCc0
-
1
def address_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_resent_cc
-
start_index = index
-
if node_cache[:obs_resent_cc].has_key?(index)
-
cached = node_cache[:obs_resent_cc][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Resent-Cc", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 9))
-
@index += 9
-
else
-
terminal_parse_failure("Resent-Cc")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_address_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsResentCc0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_resent_cc][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsResentBcc0
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_resent_bcc
-
start_index = index
-
if node_cache[:obs_resent_bcc].has_key?(index)
-
cached = node_cache[:obs_resent_bcc][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Resent-Bcc", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 10))
-
@index += 10
-
else
-
terminal_parse_failure("Resent-Bcc")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
i5 = index
-
r6 = _nt_address_list
-
if r6
-
r5 = r6
-
else
-
r8 = _nt_CFWS
-
if r8
-
r7 = r8
-
else
-
r7 = instantiate_node(SyntaxNode,input, index...index)
-
end
-
if r7
-
r5 = r7
-
else
-
@index = i5
-
r5 = nil
-
end
-
end
-
s0 << r5
-
if r5
-
r9 = _nt_CRLF
-
s0 << r9
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsResentBcc0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_resent_bcc][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsResentMid0
-
1
def msg_id
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_resent_mid
-
start_index = index
-
if node_cache[:obs_resent_mid].has_key?(index)
-
cached = node_cache[:obs_resent_mid][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Resent-Message-ID", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 17))
-
@index += 17
-
else
-
terminal_parse_failure("Resent-Message-ID")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_msg_id
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsResentMid0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_resent_mid][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsResentRply0
-
1
def address_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_resent_rply
-
start_index = index
-
if node_cache[:obs_resent_rply].has_key?(index)
-
cached = node_cache[:obs_resent_rply][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Resent-Reply-To", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 15))
-
@index += 15
-
else
-
terminal_parse_failure("Resent-Reply-To")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_address_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsResentRply0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_resent_rply][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsReturn0
-
1
def path
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_return
-
start_index = index
-
if node_cache[:obs_return].has_key?(index)
-
cached = node_cache[:obs_return][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Return-Path", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 11))
-
@index += 11
-
else
-
terminal_parse_failure("Return-Path")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_path
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsReturn0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_return][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsReceived0
-
1
def name_val_list
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_received
-
start_index = index
-
if node_cache[:obs_received].has_key?(index)
-
cached = node_cache[:obs_received][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
if has_terminal?("Received", false, index)
-
r1 = instantiate_node(SyntaxNode,input, index...(index + 8))
-
@index += 8
-
else
-
terminal_parse_failure("Received")
-
r1 = nil
-
end
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_name_val_list
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsReceived0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_received][start_index] = r0
-
-
r0
-
end
-
-
1
def _nt_obs_path
-
start_index = index
-
if node_cache[:obs_path].has_key?(index)
-
cached = node_cache[:obs_path][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
r0 = _nt_obs_angle_addr
-
-
node_cache[:obs_path][start_index] = r0
-
-
r0
-
end
-
-
1
module ObsOptional0
-
1
def field_name
-
elements[0]
-
end
-
-
1
def unstructured
-
elements[3]
-
end
-
-
1
def CRLF
-
elements[4]
-
end
-
end
-
-
1
def _nt_obs_optional
-
start_index = index
-
if node_cache[:obs_optional].has_key?(index)
-
cached = node_cache[:obs_optional][index]
-
if cached
-
cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
-
@index = cached.interval.end
-
end
-
return cached
-
end
-
-
i0, s0 = index, []
-
r1 = _nt_field_name
-
s0 << r1
-
if r1
-
s2, i2 = [], index
-
loop do
-
r3 = _nt_WSP
-
if r3
-
s2 << r3
-
else
-
break
-
end
-
end
-
r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
-
s0 << r2
-
if r2
-
if has_terminal?(":", false, index)
-
r4 = instantiate_node(SyntaxNode,input, index...(index + 1))
-
@index += 1
-
else
-
terminal_parse_failure(":")
-
r4 = nil
-
end
-
s0 << r4
-
if r4
-
r5 = _nt_unstructured
-
s0 << r5
-
if r5
-
r6 = _nt_CRLF
-
s0 << r6
-
end
-
end
-
end
-
end
-
if s0.last
-
r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
-
r0.extend(ObsOptional0)
-
else
-
@index = i0
-
r0 = nil
-
end
-
-
node_cache[:obs_optional][start_index] = r0
-
-
r0
-
end
-
-
end
-
-
1
class RFC2822ObsoleteParser < Treetop::Runtime::CompiledParser
-
1
include RFC2822Obsolete
-
end
-
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
class Part < Message
-
-
# Creates a new empty Content-ID field and inserts it in the correct order
-
# into the Header. The ContentIdField object will automatically generate
-
# a unique content ID if you try and encode it or output it to_s without
-
# specifying a content id.
-
#
-
# It will preserve the content ID you specify if you do.
-
1
def add_content_id(content_id_val = '')
-
header['content-id'] = content_id_val
-
end
-
-
# Returns true if the part has a content ID field, the field may or may
-
# not have a value, but the field exists or not.
-
1
def has_content_id?
-
header.has_content_id?
-
end
-
-
1
def inline_content_id
-
# TODO: Deprecated in 2.2.2 - Remove in 2.3
-
STDERR.puts("Part#inline_content_id is deprecated, please call Part#cid instead")
-
cid
-
end
-
-
1
def cid
-
add_content_id unless has_content_id?
-
uri_escape(unbracket(content_id))
-
end
-
-
1
def url
-
"cid:#{cid}"
-
end
-
-
1
def inline?
-
header[:content_disposition].disposition_type == 'inline' if header[:content_disposition]
-
end
-
-
1
def add_required_fields
-
super
-
add_content_id if !has_content_id? && inline?
-
end
-
-
1
def add_required_message_fields
-
# Override so we don't add Date, MIME-Version, or Message-ID.
-
end
-
-
1
def delivery_status_report_part?
-
(main_type =~ /message/i && sub_type =~ /delivery-status/i) && body =~ /Status:/
-
end
-
-
1
def delivery_status_data
-
delivery_status_report_part? ? parse_delivery_status_report : {}
-
end
-
-
1
def bounced?
-
if action.is_a?(Array)
-
!!(action.first =~ /failed/i)
-
else
-
!!(action =~ /failed/i)
-
end
-
end
-
-
-
# Either returns the action if the message has just a single report, or an
-
# array of all the actions, one for each report
-
1
def action
-
get_return_values('action')
-
end
-
-
1
def final_recipient
-
get_return_values('final-recipient')
-
end
-
-
1
def error_status
-
get_return_values('status')
-
end
-
-
1
def diagnostic_code
-
get_return_values('diagnostic-code')
-
end
-
-
1
def remote_mta
-
get_return_values('remote-mta')
-
end
-
-
1
def retryable?
-
!(error_status =~ /^5/)
-
end
-
-
1
private
-
-
1
def get_return_values(key)
-
if delivery_status_data[key].is_a?(Array)
-
delivery_status_data[key].map { |a| a.value }
-
else
-
delivery_status_data[key].value
-
end
-
end
-
-
# A part may not have a header.... so, just init a body if no header
-
1
def parse_message
-
header_part, body_part = raw_source.split(/#{CRLF}#{WSP}*#{CRLF}/m, 2)
-
if header_part =~ HEADER_LINE
-
self.header = header_part
-
self.body = body_part
-
else
-
self.header = "Content-Type: text/plain\r\n"
-
self.body = raw_source
-
end
-
end
-
-
1
def parse_delivery_status_report
-
@delivery_status_data ||= Header.new(body.to_s.gsub("\r\n\r\n", "\r\n"))
-
end
-
-
end
-
-
end
-
1
module Mail
-
1
class PartsList < Array
-
-
1
def attachments
-
4
Mail::AttachmentsList.new(self)
-
end
-
-
1
def collect
-
4
if block_given?
-
4
ary = PartsList.new
-
4
each { |o| ary << yield(o) }
-
4
ary
-
else
-
to_a
-
end
-
end
-
-
1
undef :map
-
1
alias_method :map, :collect
-
-
1
def map!
-
raise NoMethodError, "#map! is not defined, please call #collect and create a new PartsList"
-
end
-
-
1
def collect!
-
raise NoMethodError, "#collect! is not defined, please call #collect and create a new PartsList"
-
end
-
-
1
def sort
-
self.class.new(super)
-
end
-
-
1
def sort!(order)
-
sorted = self.sort do |a, b|
-
# OK, 10000 is arbitrary... if anyone actually wants to explicitly sort 10000 parts of a
-
# single email message... please show me a use case and I'll put more work into this method,
-
# in the meantime, it works :)
-
get_order_value(a, order) <=> get_order_value(b, order)
-
end
-
self.clear
-
sorted.each { |p| self << p }
-
end
-
-
1
private
-
-
1
def get_order_value(part, order)
-
if part.respond_to?(:content_type)
-
order.index(part[:content_type].string.downcase) || 10000
-
else
-
10000
-
end
-
end
-
-
end
-
end
-
# encoding: us-ascii
-
1
module Mail
-
1
module Patterns
-
1
white_space = %Q|\x9\x20|
-
1
text = %Q|\x1-\x8\xB\xC\xE-\x7f|
-
1
field_name = %Q|\x21-\x39\x3b-\x7e|
-
1
qp_safe = %Q|\x20-\x3c\x3e-\x7e|
-
-
1
aspecial = %Q|()<>[]:;@\\,."| # RFC5322
-
1
tspecial = %Q|()<>@,;:\\"/[]?=| # RFC2045
-
1
sp = %Q| |
-
1
control = %Q|\x00-\x1f\x7f-\xff|
-
-
1
if control.respond_to?(:force_encoding)
-
1
control = control.force_encoding(Encoding::BINARY)
-
end
-
-
1
CRLF = /\r\n/
-
1
WSP = /[#{white_space}]/
-
1
FWS = /#{CRLF}#{WSP}*/
-
1
TEXT = /[#{text}]/ # + obs-text
-
1
FIELD_NAME = /[#{field_name}]+/
-
1
FIELD_BODY = /.+/
-
1
FIELD_LINE = /^[#{field_name}]+:\s*.+$/
-
1
FIELD_SPLIT = /^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/
-
1
HEADER_LINE = /^([#{field_name}]+:\s*.+)$/
-
-
1
QP_UNSAFE = /[^#{qp_safe}]/
-
1
QP_SAFE = /[#{qp_safe}]/
-
1
CONTROL_CHAR = /[#{control}]/n
-
1
ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{sp}]/n
-
1
PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
-
1
TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{sp}]/n
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
module Utilities
-
1
include Patterns
-
-
# Returns true if the string supplied is free from characters not allowed as an ATOM
-
1
def atom_safe?( str )
-
not ATOM_UNSAFE === str
-
end
-
-
# If the string supplied has ATOM unsafe characters in it, will return the string quoted
-
# in double quotes, otherwise returns the string unmodified
-
1
def quote_atom( str )
-
atom_safe?( str ) ? str : dquote(str)
-
end
-
-
# If the string supplied has PHRASE unsafe characters in it, will return the string quoted
-
# in double quotes, otherwise returns the string unmodified
-
1
def quote_phrase( str )
-
if RUBY_VERSION >= '1.9'
-
original_encoding = str.encoding
-
str.force_encoding('ASCII-8BIT')
-
if (PHRASE_UNSAFE === str)
-
dquote(str).force_encoding(original_encoding)
-
else
-
str.force_encoding(original_encoding)
-
end
-
else
-
(PHRASE_UNSAFE === str) ? dquote(str) : str
-
end
-
end
-
-
# Returns true if the string supplied is free from characters not allowed as a TOKEN
-
1
def token_safe?( str )
-
not TOKEN_UNSAFE === str
-
end
-
-
# If the string supplied has TOKEN unsafe characters in it, will return the string quoted
-
# in double quotes, otherwise returns the string unmodified
-
1
def quote_token( str )
-
token_safe?( str ) ? str : dquote(str)
-
end
-
-
# Wraps supplied string in double quotes and applies \-escaping as necessary,
-
# unless it is already wrapped.
-
#
-
# Example:
-
#
-
# string = 'This is a string'
-
# dquote(string) #=> '"This is a string"'
-
#
-
# string = 'This is "a string"'
-
# dquote(string #=> '"This is \"a string\"'
-
1
def dquote( str )
-
'"' + unquote(str).gsub(/[\\"]/n) {|s| '\\' + s } + '"'
-
end
-
-
# Unwraps supplied string from inside double quotes and
-
# removes any \-escaping.
-
#
-
# Example:
-
#
-
# string = '"This is a string"'
-
# unquote(string) #=> 'This is a string'
-
#
-
# string = '"This is \"a string\""'
-
# unqoute(string) #=> 'This is "a string"'
-
1
def unquote( str )
-
if str =~ /^"(.*?)"$/
-
$1.gsub(/\\(.)/, '\1')
-
else
-
str
-
end
-
end
-
-
# Wraps a string in parenthesis and escapes any that are in the string itself.
-
#
-
# Example:
-
#
-
# paren( 'This is a string' ) #=> '(This is a string)'
-
1
def paren( str )
-
RubyVer.paren( str )
-
end
-
-
# Unwraps a string from being wrapped in parenthesis
-
#
-
# Example:
-
#
-
# str = '(This is a string)'
-
# unparen( str ) #=> 'This is a string'
-
1
def unparen( str )
-
match = str.match(/^\((.*?)\)$/)
-
match ? match[1] : str
-
end
-
-
# Wraps a string in angle brackets and escapes any that are in the string itself
-
#
-
# Example:
-
#
-
# bracket( 'This is a string' ) #=> '<This is a string>'
-
1
def bracket( str )
-
RubyVer.bracket( str )
-
end
-
-
# Unwraps a string from being wrapped in parenthesis
-
#
-
# Example:
-
#
-
# str = '<This is a string>'
-
# unbracket( str ) #=> 'This is a string'
-
1
def unbracket( str )
-
match = str.match(/^\<(.*?)\>$/)
-
match ? match[1] : str
-
end
-
-
# Escape parenthesies in a string
-
#
-
# Example:
-
#
-
# str = 'This is (a) string'
-
# escape_paren( str ) #=> 'This is \(a\) string'
-
1
def escape_paren( str )
-
RubyVer.escape_paren( str )
-
end
-
-
1
def uri_escape( str )
-
uri_parser.escape(str)
-
end
-
-
1
def uri_unescape( str )
-
uri_parser.unescape(str)
-
end
-
-
1
def uri_parser
-
@uri_parser ||= URI.const_defined?(:Parser) ? URI::Parser.new : URI
-
end
-
-
# Matches two objects with their to_s values case insensitively
-
#
-
# Example:
-
#
-
# obj2 = "This_is_An_object"
-
# obj1 = :this_IS_an_object
-
# match_to_s( obj1, obj2 ) #=> true
-
1
def match_to_s( obj1, obj2 )
-
22
obj1.to_s.casecmp(obj2.to_s) == 0
-
end
-
-
# Capitalizes a string that is joined by hyphens correctly.
-
#
-
# Example:
-
#
-
# string = 'resent-from-field'
-
# capitalize_field( string ) #=> 'Resent-From-Field'
-
1
def capitalize_field( str )
-
str.to_s.split("-").map { |v| v.capitalize }.join("-")
-
end
-
-
# Takes an underscored word and turns it into a class name
-
#
-
# Example:
-
#
-
# constantize("hello") #=> "Hello"
-
# constantize("hello-there") #=> "HelloThere"
-
# constantize("hello-there-mate") #=> "HelloThereMate"
-
1
def constantize( str )
-
str.to_s.split(/[-_]/).map { |v| v.capitalize }.to_s
-
end
-
-
# Swaps out all underscores (_) for hyphens (-) good for stringing from symbols
-
# a field name.
-
#
-
# Example:
-
#
-
# string = :resent_from_field
-
# dasherize ( string ) #=> 'resent_from_field'
-
1
def dasherize( str )
-
80
str.to_s.gsub('_', '-')
-
end
-
-
# Swaps out all hyphens (-) for underscores (_) good for stringing to symbols
-
# a field name.
-
#
-
# Example:
-
#
-
# string = :resent_from_field
-
# underscoreize ( string ) #=> 'resent_from_field'
-
1
def underscoreize( str )
-
str.to_s.downcase.gsub('-', '_')
-
end
-
-
1
if RUBY_VERSION <= '1.8.6'
-
-
def map_lines( str, &block )
-
results = []
-
str.each_line do |line|
-
results << yield(line)
-
end
-
results
-
end
-
-
def map_with_index( enum, &block )
-
results = []
-
enum.each_with_index do |token, i|
-
results[i] = yield(token, i)
-
end
-
results
-
end
-
-
else
-
-
1
def map_lines( str, &block )
-
str.each_line.map(&block)
-
end
-
-
1
def map_with_index( enum, &block )
-
enum.each_with_index.map(&block)
-
end
-
-
end
-
-
end
-
end
-
# encoding: utf-8
-
1
module Mail
-
1
module VERSION
-
-
1
version = {}
-
1
File.read(File.join(File.dirname(__FILE__), '../', 'VERSION')).each_line do |line|
-
4
type, value = line.chomp.split(":")
-
4
next if type =~ /^\s+$/ || value =~ /^\s+$/
-
4
version[type] = value
-
end
-
-
1
MAJOR = version['major']
-
1
MINOR = version['minor']
-
1
PATCH = version['patch']
-
1
BUILD = version['build']
-
-
1
STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
-
-
1
def self.version
-
STRING
-
end
-
-
end
-
end
-
# encoding: utf-8
-
-
1
module Mail
-
1
class Ruby19
-
-
# Escapes any parenthesis in a string that are unescaped this uses
-
# a Ruby 1.9.1 regexp feature of negative look behind
-
1
def Ruby19.escape_paren( str )
-
re = /(?<!\\)([\(\)])/ # Only match unescaped parens
-
str.gsub(re) { |s| '\\' + s }
-
end
-
-
1
def Ruby19.paren( str )
-
str = $1 if str =~ /^\((.*)?\)$/
-
str = escape_paren( str )
-
'(' + str + ')'
-
end
-
-
1
def Ruby19.escape_bracket( str )
-
re = /(?<!\\)([\<\>])/ # Only match unescaped brackets
-
str.gsub(re) { |s| '\\' + s }
-
end
-
-
1
def Ruby19.bracket( str )
-
str = $1 if str =~ /^\<(.*)?\>$/
-
str = escape_bracket( str )
-
'<' + str + '>'
-
end
-
-
1
def Ruby19.decode_base64(str)
-
str.unpack( 'm' ).first
-
end
-
-
1
def Ruby19.encode_base64(str)
-
[str].pack( 'm' )
-
end
-
-
1
def Ruby19.has_constant?(klass, string)
-
klass.const_defined?( string, false )
-
end
-
-
1
def Ruby19.get_constant(klass, string)
-
klass.const_get( string )
-
end
-
-
1
def Ruby19.b_value_encode(str, encoding = nil)
-
encoding = str.encoding.to_s
-
[Ruby19.encode_base64(str), encoding]
-
end
-
-
1
def Ruby19.b_value_decode(str)
-
match = str.match(/\=\?(.+)?\?[Bb]\?(.+)?\?\=/m)
-
if match
-
charset = match[1]
-
str = Ruby19.decode_base64(match[2])
-
str.force_encoding(pick_encoding(charset))
-
end
-
decoded = str.encode("utf-8", :invalid => :replace, :replace => "")
-
decoded.valid_encoding? ? decoded : decoded.encode("utf-16le", :invalid => :replace, :replace => "").encode("utf-8")
-
end
-
-
1
def Ruby19.q_value_encode(str, encoding = nil)
-
encoding = str.encoding.to_s
-
[Encodings::QuotedPrintable.encode(str), encoding]
-
end
-
-
1
def Ruby19.q_value_decode(str)
-
match = str.match(/\=\?(.+)?\?[Qq]\?(.+)?\?\=/m)
-
if match
-
charset = match[1]
-
string = match[2].gsub(/_/, '=20')
-
# Remove trailing = if it exists in a Q encoding
-
string = string.sub(/\=$/, '')
-
str = Encodings::QuotedPrintable.decode(string)
-
str.force_encoding(pick_encoding(charset))
-
end
-
decoded = str.encode("utf-8", :invalid => :replace, :replace => "")
-
decoded.valid_encoding? ? decoded : decoded.encode("utf-16le", :invalid => :replace, :replace => "").encode("utf-8")
-
rescue Encoding::UndefinedConversionError
-
str.dup.force_encoding("utf-8")
-
end
-
-
1
def Ruby19.param_decode(str, encoding)
-
string = uri_parser.unescape(str)
-
string.force_encoding(encoding) if encoding
-
string
-
end
-
-
1
def Ruby19.param_encode(str)
-
encoding = str.encoding.to_s.downcase
-
language = Configuration.instance.param_encode_language
-
"#{encoding}'#{language}'#{uri_parser.escape(str)}"
-
end
-
-
1
def Ruby19.uri_parser
-
@uri_parser ||= URI::Parser.new
-
end
-
-
# Pick a Ruby encoding corresponding to the message charset. Most
-
# charsets have a Ruby encoding, but some need manual aliasing here.
-
#
-
# TODO: add this as a test somewhere:
-
# Encoding.list.map { |e| [e.to_s.upcase == pick_encoding(e.to_s.downcase.gsub("-", "")), e.to_s] }.select {|a,b| !b}
-
# Encoding.list.map { |e| [e.to_s == pick_encoding(e.to_s), e.to_s] }.select {|a,b| !b}
-
1
def Ruby19.pick_encoding(charset)
-
case charset
-
-
# ISO-8859-15, ISO-2022-JP and alike
-
when /iso-?(\d{4})-?(\w{1,2})/i
-
"ISO-#{$1}-#{$2}"
-
-
# "ISO-2022-JP-KDDI" and alike
-
when /iso-?(\d{4})-?(\w{1,2})-?(\w*)/i
-
"ISO-#{$1}-#{$2}-#{$3}"
-
-
# UTF-8, UTF-32BE and alike
-
when /utf-?(\d{1,2})?(\w{1,2})/i
-
"UTF-#{$1}#{$2}".gsub(/\A(UTF-(?:16|32))\z/, '\\1BE')
-
-
# Windows-1252 and alike
-
when /Windows-?(.*)/i
-
"Windows-#{$1}"
-
-
when /^8bit$/
-
Encoding::ASCII_8BIT
-
-
# Microsoft-specific alias for CP949 (Korean)
-
when 'ks_c_5601-1987'
-
Encoding::CP949
-
-
# Wrongly written Shift_JIS (Japanese)
-
when 'shift-jis'
-
Encoding::Shift_JIS
-
-
# GB2312 (Chinese charset) is a subset of GB18030 (its replacement)
-
when /gb2312/i
-
Encoding::GB18030
-
-
else
-
charset
-
end
-
end
-
end
-
end
-
# -*- ruby encoding: utf-8 -*-
-
-
# The namespace for MIME applications, tools, and libraries.
-
1
module MIME
-
# Reflects a MIME Content-Type which is in invalid format (e.g., it isn't
-
# in the form of type/subtype).
-
1
class InvalidContentType < RuntimeError; end
-
-
# The definition of one MIME content-type.
-
#
-
# == Usage
-
# require 'mime/types'
-
#
-
# plaintext = MIME::Types['text/plain'].first
-
# # returns [text/plain, text/plain]
-
# text = plaintext.first
-
# print text.media_type # => 'text'
-
# print text.sub_type # => 'plain'
-
#
-
# puts text.extensions.join(" ") # => 'asc txt c cc h hh cpp'
-
#
-
# puts text.encoding # => 8bit
-
# puts text.binary? # => false
-
# puts text.ascii? # => true
-
# puts text == 'text/plain' # => true
-
# puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip'
-
#
-
# puts MIME::Types.any? { |type|
-
# type.content_type == 'text/plain'
-
# } # => true
-
# puts MIME::Types.all?(&:registered?)
-
# # => false
-
#
-
1
class Type
-
# The released version of Ruby MIME::Types
-
1
VERSION = '1.25.1'
-
-
1
include Comparable
-
-
1
MEDIA_TYPE_RE = %r{([-\w.+]+)/([-\w.+]*)}o
-
1
UNREG_RE = %r{[Xx]-}o
-
1
ENCODING_RE = %r{(?:base64|7bit|8bit|quoted\-printable)}o
-
1
PLATFORM_RE = %r|#{RUBY_PLATFORM}|o
-
-
1
SIGNATURES = %w(application/pgp-keys application/pgp
-
application/pgp-signature application/pkcs10
-
application/pkcs7-mime application/pkcs7-signature
-
text/vcard)
-
-
1
IANA_URL = "http://www.iana.org/assignments/media-types/%s/%s"
-
1
RFC_URL = "http://rfc-editor.org/rfc/rfc%s.txt"
-
1
DRAFT_URL = "http://datatracker.ietf.org/public/idindex.cgi?command=id_details&filename=%s"
-
1
LTSW_URL = "http://www.ltsw.se/knbase/internet/%s.htp"
-
1
CONTACT_URL = "http://www.iana.org/assignments/contact-people.htm#%s"
-
-
# Returns +true+ if the simplified type matches the current
-
1
def like?(other)
-
if other.respond_to?(:simplified)
-
@simplified == other.simplified
-
else
-
@simplified == Type.simplified(other)
-
end
-
end
-
-
# Compares the MIME::Type against the exact content type or the
-
# simplified type (the simplified type will be used if comparing against
-
# something that can be treated as a String with #to_s). In comparisons,
-
# this is done against the lowercase version of the MIME::Type.
-
1
def <=>(other)
-
74
if other.respond_to?(:content_type)
-
74
@content_type.downcase <=> other.content_type.downcase
-
elsif other.respond_to?(:to_s)
-
@simplified <=> Type.simplified(other.to_s)
-
else
-
@content_type.downcase <=> other.downcase
-
end
-
end
-
-
# Compares the MIME::Type based on how reliable it is before doing a
-
# normal <=> comparison. Used by MIME::Types#[] to sort types. The
-
# comparisons involved are:
-
#
-
# 1. self.simplified <=> other.simplified (ensures that we
-
# don't try to compare different types)
-
# 2. IANA-registered definitions < other definitions.
-
# 3. Generic definitions < platform definitions.
-
# 3. Complete definitions < incomplete definitions.
-
# 4. Current definitions < obsolete definitions.
-
# 5. Obselete with use-instead references < obsolete without.
-
# 6. Obsolete use-instead definitions are compared.
-
1
def priority_compare(other)
-
pc = simplified <=> other.simplified
-
-
if pc.zero?
-
pc = if registered? != other.registered?
-
registered? ? -1 : 1 # registered < unregistered
-
elsif platform? != other.platform?
-
platform? ? 1 : -1 # generic < platform
-
elsif complete? != other.complete?
-
complete? ? -1 : 1 # complete < incomplete
-
elsif obsolete? != other.obsolete?
-
obsolete? ? 1 : -1 # current < obsolete
-
else
-
0
-
end
-
-
if pc.zero? and obsolete? and (use_instead != other.use_instead)
-
pc = if use_instead.nil?
-
-1
-
elsif other.use_instead.nil?
-
1
-
else
-
use_instead <=> other.use_instead
-
end
-
end
-
end
-
-
pc
-
end
-
-
# Returns +true+ if the other object is a MIME::Type and the content
-
# types match.
-
1
def eql?(other)
-
other.kind_of?(MIME::Type) and self == other
-
end
-
-
# Returns the whole MIME content-type string.
-
#
-
# text/plain => text/plain
-
# x-chemical/x-pdb => x-chemical/x-pdb
-
1
attr_reader :content_type
-
# Returns the media type of the simplified MIME type.
-
#
-
# text/plain => text
-
# x-chemical/x-pdb => chemical
-
1
attr_reader :media_type
-
# Returns the media type of the unmodified MIME type.
-
#
-
# text/plain => text
-
# x-chemical/x-pdb => x-chemical
-
1
attr_reader :raw_media_type
-
# Returns the sub-type of the simplified MIME type.
-
#
-
# text/plain => plain
-
# x-chemical/x-pdb => pdb
-
1
attr_reader :sub_type
-
# Returns the media type of the unmodified MIME type.
-
#
-
# text/plain => plain
-
# x-chemical/x-pdb => x-pdb
-
1
attr_reader :raw_sub_type
-
# The MIME types main- and sub-label can both start with <tt>x-</tt>,
-
# which indicates that it is a non-registered name. Of course, after
-
# registration this flag can disappear, adds to the confusing
-
# proliferation of MIME types. The simplified string has the <tt>x-</tt>
-
# removed and are translated to lowercase.
-
#
-
# text/plain => text/plain
-
# x-chemical/x-pdb => chemical/pdb
-
1
attr_reader :simplified
-
# The list of extensions which are known to be used for this MIME::Type.
-
# Non-array values will be coerced into an array with #to_a. Array
-
# values will be flattened and +nil+ values removed.
-
1
attr_accessor :extensions
-
1
remove_method :extensions= ;
-
1
def extensions=(ext) #:nodoc:
-
3286
@extensions = [ext].flatten.compact
-
end
-
-
# The encoding (7bit, 8bit, quoted-printable, or base64) required to
-
# transport the data of this content type safely across a network, which
-
# roughly corresponds to Content-Transfer-Encoding. A value of +nil+ or
-
# <tt>:default</tt> will reset the #encoding to the #default_encoding
-
# for the MIME::Type. Raises ArgumentError if the encoding provided is
-
# invalid.
-
#
-
# If the encoding is not provided on construction, this will be either
-
# 'quoted-printable' (for text/* media types) and 'base64' for eveything
-
# else.
-
1
attr_accessor :encoding
-
1
remove_method :encoding= ;
-
1
def encoding=(enc) #:nodoc:
-
3286
if enc.nil? or enc == :default
-
3129
@encoding = self.default_encoding
-
157
elsif enc =~ ENCODING_RE
-
157
@encoding = enc
-
else
-
raise ArgumentError, "The encoding must be nil, :default, base64, 7bit, 8bit, or quoted-printable."
-
end
-
end
-
-
# The regexp for the operating system that this MIME::Type is specific
-
# to.
-
1
attr_accessor :system
-
1
remove_method :system= ;
-
1
def system=(os) #:nodoc:
-
3286
if os.nil? or os.kind_of?(Regexp)
-
3282
@system = os
-
else
-
4
@system = %r|#{os}|
-
end
-
end
-
# Returns the default encoding for the MIME::Type based on the media
-
# type.
-
1
attr_reader :default_encoding
-
1
remove_method :default_encoding
-
1
def default_encoding
-
3129
(@media_type == 'text') ? 'quoted-printable' : 'base64'
-
end
-
-
# Returns the media type or types that should be used instead of this
-
# media type, if it is obsolete. If there is no replacement media type,
-
# or it is not obsolete, +nil+ will be returned.
-
1
attr_reader :use_instead
-
1
remove_method :use_instead
-
1
def use_instead
-
return nil unless @obsolete
-
@use_instead
-
end
-
-
# Returns +true+ if the media type is obsolete.
-
1
def obsolete?
-
@obsolete ? true : false
-
end
-
# Sets the obsolescence indicator for this media type.
-
1
attr_writer :obsolete
-
-
# The documentation for this MIME::Type. Documentation about media
-
# types will be found on a media type definition as a comment.
-
# Documentation will be found through #docs.
-
1
attr_accessor :docs
-
1
remove_method :docs= ;
-
1
def docs=(d)
-
3286
if d
-
45
a = d.scan(%r{use-instead:#{MEDIA_TYPE_RE}})
-
-
45
if a.empty?
-
2
@use_instead = nil
-
else
-
86
@use_instead = a.map { |el| "#{el[0]}/#{el[1]}" }
-
end
-
end
-
3286
@docs = d
-
end
-
-
# The encoded URL list for this MIME::Type. See #urls for more
-
# information.
-
1
attr_accessor :url
-
# The decoded URL list for this MIME::Type.
-
# The special URL value IANA will be translated into:
-
# http://www.iana.org/assignments/media-types/<mediatype>/<subtype>
-
#
-
# The special URL value RFC### will be translated into:
-
# http://www.rfc-editor.org/rfc/rfc###.txt
-
#
-
# The special URL value DRAFT:name will be translated into:
-
# https://datatracker.ietf.org/public/idindex.cgi?
-
# command=id_detail&filename=<name>
-
#
-
# The special URL value LTSW will be translated into:
-
# http://www.ltsw.se/knbase/internet/<mediatype>.htp
-
#
-
# The special URL value [token] will be translated into:
-
# http://www.iana.org/assignments/contact-people.htm#<token>
-
#
-
# These values will be accessible through #urls, which always returns an
-
# array.
-
1
def urls
-
@url.map do |el|
-
case el
-
when %r{^IANA$}
-
IANA_URL % [ @media_type, @sub_type ]
-
when %r{^RFC(\d+)$}
-
RFC_URL % $1
-
when %r{^DRAFT:(.+)$}
-
DRAFT_URL % $1
-
when %r{^LTSW$}
-
LTSW_URL % @media_type
-
when %r{^\{([^=]+)=([^\}]+)\}}
-
[$1, $2]
-
when %r{^\[([^=]+)=([^\]]+)\]}
-
[$1, CONTACT_URL % $2]
-
when %r{^\[([^\]]+)\]}
-
CONTACT_URL % $1
-
else
-
el
-
end
-
end
-
end
-
-
1
class << self
-
# The MIME types main- and sub-label can both start with <tt>x-</tt>,
-
# which indicates that it is a non-registered name. Of course, after
-
# registration this flag can disappear, adds to the confusing
-
# proliferation of MIME types. The simplified string has the
-
# <tt>x-</tt> removed and are translated to lowercase.
-
1
def simplified(content_type)
-
1643
matchdata = MEDIA_TYPE_RE.match(content_type)
-
-
1643
if matchdata.nil?
-
simplified = nil
-
else
-
1643
media_type = matchdata.captures[0].downcase.gsub(UNREG_RE, '')
-
1643
subtype = matchdata.captures[1].downcase.gsub(UNREG_RE, '')
-
1643
simplified = "#{media_type}/#{subtype}"
-
end
-
1643
simplified
-
end
-
-
# Creates a MIME::Type from an array in the form of:
-
# [type-name, [extensions], encoding, system]
-
#
-
# +extensions+, +encoding+, and +system+ are optional.
-
#
-
# MIME::Type.from_array("application/x-ruby", ['rb'], '8bit')
-
# MIME::Type.from_array(["application/x-ruby", ['rb'], '8bit'])
-
#
-
# These are equivalent to:
-
#
-
# MIME::Type.new('application/x-ruby') do |t|
-
# t.extensions = %w(rb)
-
# t.encoding = '8bit'
-
# end
-
1
def from_array(*args) #:yields MIME::Type.new:
-
# Dereferences the array one level, if necessary.
-
args = args.first if args.first.kind_of? Array
-
-
unless args.size.between?(1, 8)
-
raise ArgumentError, "Array provided must contain between one and eight elements."
-
end
-
-
MIME::Type.new(args.shift) do |t|
-
t.extensions, t.encoding, t.system, t.obsolete, t.docs, t.url,
-
t.registered = *args
-
yield t if block_given?
-
end
-
end
-
-
# Creates a MIME::Type from a hash. Keys are case-insensitive,
-
# dashes may be replaced with underscores, and the internal Symbol
-
# of the lowercase-underscore version can be used as well. That is,
-
# Content-Type can be provided as content-type, Content_Type,
-
# content_type, or :content_type.
-
#
-
# Known keys are <tt>Content-Type</tt>,
-
# <tt>Content-Transfer-Encoding</tt>, <tt>Extensions</tt>, and
-
# <tt>System</tt>.
-
#
-
# MIME::Type.from_hash('Content-Type' => 'text/x-yaml',
-
# 'Content-Transfer-Encoding' => '8bit',
-
# 'System' => 'linux',
-
# 'Extensions' => ['yaml', 'yml'])
-
#
-
# This is equivalent to:
-
#
-
# MIME::Type.new('text/x-yaml') do |t|
-
# t.encoding = '8bit'
-
# t.system = 'linux'
-
# t.extensions = ['yaml', 'yml']
-
# end
-
1
def from_hash(hash) #:yields MIME::Type.new:
-
type = {}
-
hash.each_pair do |k, v|
-
type[k.to_s.tr('A-Z', 'a-z').gsub(/-/, '_').to_sym] = v
-
end
-
-
MIME::Type.new(type[:content_type]) do |t|
-
t.extensions = type[:extensions]
-
t.encoding = type[:content_transfer_encoding]
-
t.system = type[:system]
-
t.obsolete = type[:obsolete]
-
t.docs = type[:docs]
-
t.url = type[:url]
-
t.registered = type[:registered]
-
-
yield t if block_given?
-
end
-
end
-
-
# Essentially a copy constructor.
-
#
-
# MIME::Type.from_mime_type(plaintext)
-
#
-
# is equivalent to:
-
#
-
# MIME::Type.new(plaintext.content_type.dup) do |t|
-
# t.extensions = plaintext.extensions.dup
-
# t.system = plaintext.system.dup
-
# t.encoding = plaintext.encoding.dup
-
# end
-
1
def from_mime_type(mime_type) #:yields the new MIME::Type:
-
MIME::Type.new(mime_type.content_type.dup) do |t|
-
t.extensions = mime_type.extensions.map { |e| e.dup }
-
t.url = mime_type.url && mime_type.url.map { |e| e.dup }
-
-
mime_type.system && t.system = mime_type.system.dup
-
mime_type.encoding && t.encoding = mime_type.encoding.dup
-
-
t.obsolete = mime_type.obsolete?
-
t.registered = mime_type.registered?
-
-
mime_type.docs && t.docs = mime_type.docs.dup
-
-
yield t if block_given?
-
end
-
end
-
end
-
-
# Builds a MIME::Type object from the provided MIME Content Type value
-
# (e.g., 'text/plain' or 'applicaton/x-eruby'). The constructed object
-
# is yielded to an optional block for additional configuration, such as
-
# associating extensions and encoding information.
-
1
def initialize(content_type) #:yields self:
-
1643
matchdata = MEDIA_TYPE_RE.match(content_type)
-
-
1643
if matchdata.nil?
-
raise InvalidContentType, "Invalid Content-Type provided ('#{content_type}')"
-
end
-
-
1643
@content_type = content_type
-
1643
@raw_media_type = matchdata.captures[0]
-
1643
@raw_sub_type = matchdata.captures[1]
-
-
1643
@simplified = MIME::Type.simplified(@content_type)
-
1643
matchdata = MEDIA_TYPE_RE.match(@simplified)
-
1643
@media_type = matchdata.captures[0]
-
1643
@sub_type = matchdata.captures[1]
-
-
1643
self.extensions = nil
-
1643
self.encoding = :default
-
1643
self.system = nil
-
1643
self.registered = true
-
1643
self.url = nil
-
1643
self.obsolete = nil
-
1643
self.docs = nil
-
-
1643
yield self if block_given?
-
end
-
-
# MIME content-types which are not regestered by IANA nor defined in
-
# RFCs are required to start with <tt>x-</tt>. This counts as well for
-
# a new media type as well as a new sub-type of an existing media
-
# type. If either the media-type or the content-type begins with
-
# <tt>x-</tt>, this method will return +false+.
-
1
def registered?
-
if (@raw_media_type =~ UNREG_RE) || (@raw_sub_type =~ UNREG_RE)
-
false
-
else
-
@registered
-
end
-
end
-
1
attr_writer :registered #:nodoc:
-
-
# MIME types can be specified to be sent across a network in particular
-
# formats. This method returns +true+ when the MIME type encoding is set
-
# to <tt>base64</tt>.
-
1
def binary?
-
@encoding == 'base64'
-
end
-
-
# MIME types can be specified to be sent across a network in particular
-
# formats. This method returns +false+ when the MIME type encoding is
-
# set to <tt>base64</tt>.
-
1
def ascii?
-
not binary?
-
end
-
-
# Returns +true+ when the simplified MIME type is in the list of known
-
# digital signatures.
-
1
def signature?
-
SIGNATURES.include?(@simplified.downcase)
-
end
-
-
# Returns +true+ if the MIME::Type is specific to an operating system.
-
1
def system?
-
not @system.nil?
-
end
-
-
# Returns +true+ if the MIME::Type is specific to the current operating
-
# system as represented by RUBY_PLATFORM.
-
1
def platform?
-
system? and (RUBY_PLATFORM =~ @system)
-
end
-
-
# Returns +true+ if the MIME::Type specifies an extension list,
-
# indicating that it is a complete MIME::Type.
-
1
def complete?
-
not @extensions.empty?
-
end
-
-
# Returns the MIME type as a string.
-
1
def to_s
-
@content_type
-
end
-
-
# Returns the MIME type as a string for implicit conversions.
-
1
def to_str
-
@content_type
-
end
-
-
# Returns the MIME type as an array suitable for use with
-
# MIME::Type.from_array.
-
1
def to_a
-
[ @content_type, @extensions, @encoding, @system, @obsolete, @docs,
-
@url, registered? ]
-
end
-
-
# Returns the MIME type as an array suitable for use with
-
# MIME::Type.from_hash.
-
1
def to_hash
-
{ 'Content-Type' => @content_type,
-
'Content-Transfer-Encoding' => @encoding,
-
'Extensions' => @extensions,
-
'System' => @system,
-
'Obsolete' => @obsolete,
-
'Docs' => @docs,
-
'URL' => @url,
-
'Registered' => registered?,
-
}
-
end
-
end
-
-
# = MIME::Types
-
# MIME types are used in MIME-compliant communications, as in e-mail or
-
# HTTP traffic, to indicate the type of content which is transmitted.
-
# MIME::Types provides the ability for detailed information about MIME
-
# entities (provided as a set of MIME::Type objects) to be determined and
-
# used programmatically. There are many types defined by RFCs and vendors,
-
# so the list is long but not complete; don't hesitate to ask to add
-
# additional information. This library follows the IANA collection of MIME
-
# types (see below for reference).
-
#
-
# == Description
-
# MIME types are used in MIME entities, as in email or HTTP traffic. It is
-
# useful at times to have information available about MIME types (or,
-
# inversely, about files). A MIME::Type stores the known information about
-
# one MIME type.
-
#
-
# == Usage
-
# require 'mime/types'
-
#
-
# plaintext = MIME::Types['text/plain']
-
# print plaintext.media_type # => 'text'
-
# print plaintext.sub_type # => 'plain'
-
#
-
# puts plaintext.extensions.join(" ") # => 'asc txt c cc h hh cpp'
-
#
-
# puts plaintext.encoding # => 8bit
-
# puts plaintext.binary? # => false
-
# puts plaintext.ascii? # => true
-
# puts plaintext.obsolete? # => false
-
# puts plaintext.registered? # => true
-
# puts plaintext == 'text/plain' # => true
-
# puts MIME::Type.simplified('x-appl/x-zip') # => 'appl/zip'
-
#
-
# This module is built to conform to the MIME types of RFCs 2045 and 2231.
-
# It follows the official IANA registry at
-
# http://www.iana.org/assignments/media-types/ and
-
# ftp://ftp.iana.org/assignments/media-types with some unofficial types
-
# added from the the collection at
-
# http://www.ltsw.se/knbase/internet/mime.htp
-
1
class Types
-
# The released version of Ruby MIME::Types
-
1
VERSION = MIME::Type::VERSION
-
1
DATA_VERSION = (VERSION.to_f * 100).to_i
-
-
# The data version.
-
1
attr_reader :data_version
-
-
1
class HashWithArrayDefault < Hash # :nodoc:
-
1
def initialize
-
4410
super { |h, k| h[k] = [] }
-
end
-
-
1
def marshal_dump
-
{}.merge(self)
-
end
-
-
1
def marshal_load(hash)
-
self.merge!(hash)
-
end
-
end
-
-
1
class CacheContainer # :nodoc:
-
1
attr_reader :version, :data
-
1
def initialize(version, data)
-
@version, @data = version, data
-
end
-
end
-
-
1
def initialize(data_version = DATA_VERSION)
-
25
@type_variants = HashWithArrayDefault.new
-
25
@extension_index = HashWithArrayDefault.new
-
25
@data_version = data_version
-
end
-
-
1
def add_type_variant(mime_type) #:nodoc:
-
3286
@type_variants[mime_type.simplified] << mime_type
-
end
-
-
1
def index_extensions(mime_type) #:nodoc:
-
4558
mime_type.extensions.each { |ext| @extension_index[ext] << mime_type }
-
end
-
-
1
def defined_types #:nodoc:
-
24
@type_variants.values.flatten
-
end
-
-
# Returns the number of known types. A shortcut of MIME::Types[//].size.
-
# (Keep in mind that this is memory intensive, cache the result to spare
-
# resources)
-
1
def count
-
defined_types.size
-
end
-
-
1
def each
-
defined_types.each { |t| yield t }
-
end
-
-
1
@__types__ = nil
-
-
# Returns a list of MIME::Type objects, which may be empty. The optional
-
# flag parameters are :complete (finds only complete MIME::Type objects)
-
# and :platform (finds only MIME::Types for the current platform). It is
-
# possible for multiple matches to be returned for either type (in the
-
# example below, 'text/plain' returns two values -- one for the general
-
# case, and one for VMS systems.
-
#
-
# puts "\nMIME::Types['text/plain']"
-
# MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") }
-
#
-
# puts "\nMIME::Types[/^image/, :complete => true]"
-
# MIME::Types[/^image/, :complete => true].each do |t|
-
# puts t.to_a.join(", ")
-
# end
-
#
-
# If multiple type definitions are returned, returns them sorted as
-
# follows:
-
# 1. Complete definitions sort before incomplete ones;
-
# 2. IANA-registered definitions sort before LTSW-recorded
-
# definitions.
-
# 3. Generic definitions sort before platform-specific ones;
-
# 4. Current definitions sort before obsolete ones;
-
# 5. Obsolete definitions with use-instead clauses sort before those
-
# without;
-
# 6. Obsolete definitions use-instead clauses are compared.
-
# 7. Sort on name.
-
1
def [](type_id, flags = {})
-
matches = case type_id
-
when MIME::Type
-
@type_variants[type_id.simplified]
-
when Regexp
-
match(type_id)
-
else
-
@type_variants[MIME::Type.simplified(type_id)]
-
end
-
-
prune_matches(matches, flags).sort { |a, b| a.priority_compare(b) }
-
end
-
-
# Return the list of MIME::Types which belongs to the file based on its
-
# filename extension. If +platform+ is +true+, then only file types that
-
# are specific to the current platform will be returned.
-
#
-
# This will always return an array.
-
#
-
# puts "MIME::Types.type_for('citydesk.xml')
-
# => [application/xml, text/xml]
-
# puts "MIME::Types.type_for('citydesk.gif')
-
# => [image/gif]
-
1
def type_for(filename, platform = false)
-
ext = filename.chomp.downcase.gsub(/.*\./o, '')
-
list = @extension_index[ext]
-
list.delete_if { |e| not e.platform? } if platform
-
list
-
end
-
-
# A synonym for MIME::Types.type_for
-
1
def of(filename, platform = false)
-
type_for(filename, platform)
-
end
-
-
# Add one or more MIME::Type objects to the set of known types. Each
-
# type should be experimental (e.g., 'application/x-ruby'). If the type
-
# is already known, a warning will be displayed.
-
#
-
# <strong>Please inform the maintainer of this module when registered
-
# types are missing.</strong>
-
1
def add(*types)
-
1691
types.each do |mime_type|
-
3310
if mime_type.kind_of? MIME::Types
-
24
add(*mime_type.defined_types)
-
else
-
3286
if @type_variants.include?(mime_type.simplified)
-
73
if @type_variants[mime_type.simplified].include?(mime_type)
-
6
warn "Type #{mime_type} already registered as a variant of #{mime_type.simplified}." unless defined? MIME::Types::LOAD
-
end
-
end
-
3286
add_type_variant(mime_type)
-
3286
index_extensions(mime_type)
-
end
-
end
-
end
-
-
1
private
-
1
def prune_matches(matches, flags)
-
matches.delete_if { |e| not e.complete? } if flags[:complete]
-
matches.delete_if { |e| not e.platform? } if flags[:platform]
-
matches
-
end
-
-
1
def match(pattern)
-
matches = @type_variants.select { |k, v| k =~ pattern }
-
if matches.respond_to? :values
-
matches.values.flatten
-
else
-
matches.map { |m| m.last }.flatten
-
end
-
end
-
-
1
class << self
-
1
def add_type_variant(mime_type) #:nodoc:
-
__types__.add_type_variant(mime_type)
-
end
-
-
1
def index_extensions(mime_type) #:nodoc:
-
__types__.index_extensions(mime_type)
-
end
-
-
# The regular expression used to match a file-based MIME type
-
# definition.
-
1
TEXT_FORMAT_RE = %r{
-
\A
-
\s*
-
([*])? # 0: Unregistered?
-
(!)? # 1: Obsolete?
-
(?:(\w+):)? # 2: Platform marker
-
#{MIME::Type::MEDIA_TYPE_RE}? # 3,4: Media type
-
(?:\s+@([^\s]+))? # 5: Extensions
-
(?:\s+:(#{MIME::Type::ENCODING_RE}))? # 6: Encoding
-
(?:\s+'(.+))? # 7: URL list
-
(?:\s+=(.+))? # 8: Documentation
-
(?:\s*([#].*)?)?
-
\s*
-
\z
-
}x
-
-
# Build the type list from a file in the format:
-
#
-
# [*][!][os:]mt/st[<ws>@ext][<ws>:enc][<ws>'url-list][<ws>=docs]
-
#
-
# == *
-
# An unofficial MIME type. This should be used if and only if the MIME type
-
# is not properly specified (that is, not under either x-type or
-
# vnd.name.type).
-
#
-
# == !
-
# An obsolete MIME type. May be used with an unofficial MIME type.
-
#
-
# == os:
-
# Platform-specific MIME type definition.
-
#
-
# == mt
-
# The media type.
-
#
-
# == st
-
# The media subtype.
-
#
-
# == <ws>@ext
-
# The list of comma-separated extensions.
-
#
-
# == <ws>:enc
-
# The encoding.
-
#
-
# == <ws>'url-list
-
# The list of comma-separated URLs.
-
#
-
# == <ws>=docs
-
# The documentation string.
-
#
-
# That is, everything except the media type and the subtype is optional. The
-
# more information that's available, though, the richer the values that can
-
# be provided.
-
1
def load_from_file(filename) #:nodoc:
-
24
if defined? ::Encoding
-
48
data = File.open(filename, 'r:UTF-8:-') { |f| f.read }
-
else
-
data = File.open(filename) { |f| f.read }
-
end
-
24
data = data.split($/)
-
24
mime = MIME::Types.new
-
24
data.each_with_index { |line, index|
-
1643
item = line.chomp.strip
-
1643
next if item.empty?
-
-
1643
begin
-
1643
m = TEXT_FORMAT_RE.match(item).captures
-
rescue Exception
-
puts "#{filename}:#{index}: Parsing error in MIME type definitions."
-
puts "=> #{line}"
-
raise
-
end
-
-
unregistered, obsolete, platform, mediatype, subtype, extensions,
-
1643
encoding, urls, docs, comment = *m
-
-
1643
if mediatype.nil?
-
if comment.nil?
-
puts "#{filename}:#{index}: Parsing error in MIME type definitions."
-
puts "=> #{line}"
-
raise RuntimeError
-
end
-
-
next
-
end
-
-
1643
extensions &&= extensions.split(/,/)
-
1643
urls &&= urls.split(/,/)
-
-
1643
mime_type = MIME::Type.new("#{mediatype}/#{subtype}") do |t|
-
1643
t.extensions = extensions
-
1643
t.encoding = encoding
-
1643
t.system = platform
-
1643
t.obsolete = obsolete
-
1643
t.registered = false if unregistered
-
1643
t.docs = docs
-
1643
t.url = urls
-
end
-
-
1643
mime.add(mime_type)
-
}
-
24
mime
-
end
-
-
# Returns a list of MIME::Type objects, which may be empty. The
-
# optional flag parameters are :complete (finds only complete
-
# MIME::Type objects) and :platform (finds only MIME::Types for the
-
# current platform). It is possible for multiple matches to be
-
# returned for either type (in the example below, 'text/plain' returns
-
# two values -- one for the general case, and one for VMS systems.
-
#
-
# puts "\nMIME::Types['text/plain']"
-
# MIME::Types['text/plain'].each { |t| puts t.to_a.join(", ") }
-
#
-
# puts "\nMIME::Types[/^image/, :complete => true]"
-
# MIME::Types[/^image/, :complete => true].each do |t|
-
# puts t.to_a.join(", ")
-
# end
-
1
def [](type_id, flags = {})
-
__types__[type_id, flags]
-
end
-
-
1
include Enumerable
-
-
1
def count
-
__types__.count
-
end
-
-
1
def each
-
__types__.each {|t| yield t }
-
end
-
-
# Return the list of MIME::Types which belongs to the file based on
-
# its filename extension. If +platform+ is +true+, then only file
-
# types that are specific to the current platform will be returned.
-
#
-
# This will always return an array.
-
#
-
# puts "MIME::Types.type_for('citydesk.xml')
-
# => [application/xml, text/xml]
-
# puts "MIME::Types.type_for('citydesk.gif')
-
# => [image/gif]
-
1
def type_for(filename, platform = false)
-
__types__.type_for(filename, platform)
-
end
-
-
# A synonym for MIME::Types.type_for
-
1
def of(filename, platform = false)
-
__types__.type_for(filename, platform)
-
end
-
-
# Add one or more MIME::Type objects to the set of known types. Each
-
# type should be experimental (e.g., 'application/x-ruby'). If the
-
# type is already known, a warning will be displayed.
-
#
-
# <strong>Please inform the maintainer of this module when registered
-
# types are missing.</strong>
-
1
def add(*types)
-
24
__types__.add(*types)
-
end
-
-
# Returns the currently defined cache file, if any.
-
1
def cache_file
-
2
ENV['RUBY_MIME_TYPES_CACHE']
-
end
-
-
1
private
-
1
def load_mime_types_from_cache
-
1
load_mime_types_from_cache! if cache_file
-
end
-
-
1
def load_mime_types_from_cache!
-
raise ArgumentError, "No RUBY_MIME_TYPES_CACHE set." unless cache_file
-
return false unless File.exists? cache_file
-
-
begin
-
data = File.read(cache_file)
-
container = Marshal.load(data)
-
-
if container.version == VERSION
-
@__types__ = Marshal.load(container.data)
-
true
-
else
-
false
-
end
-
rescue => e
-
warn "Could not load MIME::Types cache: #{e}"
-
false
-
end
-
end
-
-
1
def write_mime_types_to_cache
-
1
write_mime_types_to_cache! if cache_file
-
end
-
-
1
def write_mime_types_to_cache!
-
raise ArgumentError, "No RUBY_MIME_TYPES_CACHE set." unless cache_file
-
-
File.open(cache_file, 'w') do |f|
-
cache = MIME::Types::CacheContainer.new(VERSION,
-
Marshal.dump(__types__))
-
f.write Marshal.dump(cache)
-
end
-
-
true
-
end
-
-
1
def load_and_parse_mime_types
-
1
const_set(:LOAD, true) unless $DEBUG
-
1
Dir[File.join(File.dirname(__FILE__), 'types', '*')].sort.each { |f|
-
24
add(load_from_file(f))
-
}
-
1
remove_const :LOAD if defined? LOAD
-
end
-
-
1
def lazy_load?
-
1
(lazy = ENV['RUBY_MIME_TYPES_LAZY_LOAD']) && (lazy != 'false')
-
end
-
-
1
def __types__
-
24
load_mime_types unless @__types__
-
24
@__types__
-
end
-
-
1
def load_mime_types
-
1
@__types__ = new(VERSION)
-
1
unless load_mime_types_from_cache
-
1
load_and_parse_mime_types
-
1
write_mime_types_to_cache
-
end
-
end
-
end
-
-
1
load_mime_types unless lazy_load?
-
end
-
end
-
-
# vim: ft=ruby
-
1
require 'active_support/backtrace_cleaner'
-
-
1
module Rails
-
1
class BacktraceCleaner < ActiveSupport::BacktraceCleaner
-
1
APP_DIRS_PATTERN = /^\/?(app|config|lib|test)/
-
1
RENDER_TEMPLATE_PATTERN = /:in `_render_template_\w*'/
-
-
1
def initialize
-
1
super
-
1
add_filter { |line| line.sub("#{Rails.root}/", '') }
-
1
add_filter { |line| line.sub(RENDER_TEMPLATE_PATTERN, '') }
-
1
add_filter { |line| line.sub('./', '/') } # for tests
-
-
1
add_gem_filters
-
1
add_silencer { |line| line !~ APP_DIRS_PATTERN }
-
end
-
-
1
private
-
1
def add_gem_filters
-
3
gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
-
1
return if gems_paths.empty?
-
-
1
gems_regexp = %r{(#{gems_paths.join('|')})/gems/([^/]+)-([\w.]+)/(.*)}
-
1
add_filter { |line| line.sub(gems_regexp, '\2 (\3) \4') }
-
end
-
end
-
end
-
1
require 'rspec/mocks'
-
-
1
module RSpec
-
1
module Core
-
1
module MockFrameworkAdapter
-
-
2
def self.framework_name; :rspec end
-
-
1
def self.configuration
-
RSpec::Mocks.configuration
-
end
-
-
1
def setup_mocks_for_rspec
-
27
RSpec::Mocks::setup(self)
-
end
-
-
1
def verify_mocks_for_rspec
-
27
RSpec::Mocks::verify
-
end
-
-
1
def teardown_mocks_for_rspec
-
27
RSpec::Mocks::teardown
-
end
-
-
end
-
end
-
end
-
1
module RSpec
-
1
module Matchers
-
1
module BuiltIn
-
1
class BeAKindOf < BaseMatcher
-
1
def match(expected, actual)
-
1
actual.kind_of? expected
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Matchers
-
1
module BuiltIn
-
1
class Change
-
1
def initialize(receiver=nil, message=nil, &block)
-
3
@message = message
-
9
@value_proc = block || lambda {receiver.__send__(message)}
-
3
@expected_after = @expected_before = @minimum = @maximum = @expected_delta = nil
-
3
@eval_before = @eval_after = false
-
end
-
-
1
def matches?(event_proc)
-
3
raise_block_syntax_error if block_given?
-
-
3
@actual_before = evaluate_value_proc
-
3
event_proc.call
-
3
@actual_after = evaluate_value_proc
-
-
3
(!change_expected? || changed?) && matches_before? && matches_after? && matches_expected_delta? && matches_min? && matches_max?
-
end
-
1
alias == matches?
-
-
1
def raise_block_syntax_error
-
raise SyntaxError.new(<<-MESSAGE)
-
block passed to should or should_not change must use {} instead of do/end
-
MESSAGE
-
end
-
-
1
def evaluate_value_proc
-
6
case val = @value_proc.call
-
when Enumerable, String
-
val.dup
-
else
-
6
val
-
end
-
end
-
-
1
def failure_message_for_should
-
if @eval_before && !expected_matches_actual?(@expected_before, @actual_before)
-
"#{message} should have initially been #{@expected_before.inspect}, but was #{@actual_before.inspect}"
-
elsif @eval_after && !expected_matches_actual?(@expected_after, @actual_after)
-
"#{message} should have been changed to #{@expected_after.inspect}, but is now #{@actual_after.inspect}"
-
elsif @expected_delta
-
"#{message} should have been changed by #{@expected_delta.inspect}, but was changed by #{actual_delta.inspect}"
-
elsif @minimum
-
"#{message} should have been changed by at least #{@minimum.inspect}, but was changed by #{actual_delta.inspect}"
-
elsif @maximum
-
"#{message} should have been changed by at most #{@maximum.inspect}, but was changed by #{actual_delta.inspect}"
-
else
-
"#{message} should have changed, but is still #{@actual_before.inspect}"
-
end
-
end
-
-
1
def actual_delta
-
@actual_after - @actual_before
-
end
-
-
1
def failure_message_for_should_not
-
"#{message} should not have changed, but did change from #{@actual_before.inspect} to #{@actual_after.inspect}"
-
end
-
-
1
def by(expected_delta)
-
3
@expected_delta = expected_delta
-
3
self
-
end
-
-
1
def by_at_least(minimum)
-
@minimum = minimum
-
self
-
end
-
-
1
def by_at_most(maximum)
-
@maximum = maximum
-
self
-
end
-
-
1
def to(to)
-
@eval_after = true
-
@expected_after = to
-
self
-
end
-
-
1
def from (before)
-
@eval_before = true
-
@expected_before = before
-
self
-
end
-
-
1
def description
-
"change ##{message}"
-
end
-
-
1
private
-
-
1
def message
-
@message || "result"
-
end
-
-
1
def change_expected?
-
3
@expected_delta != 0
-
end
-
-
1
def changed?
-
3
@actual_before != @actual_after
-
end
-
-
1
def matches_before?
-
3
@eval_before ? expected_matches_actual?(@expected_before, @actual_before) : true
-
end
-
-
1
def matches_after?
-
3
@eval_after ? expected_matches_actual?(@expected_after, @actual_after) : true
-
end
-
-
1
def matches_expected_delta?
-
3
@expected_delta ? (@actual_before + @expected_delta == @actual_after) : true
-
end
-
-
1
def matches_min?
-
3
@minimum ? (@actual_after - @actual_before >= @minimum) : true
-
end
-
-
1
def matches_max?
-
3
@maximum ? (@actual_after - @actual_before <= @maximum) : true
-
end
-
-
1
def expected_matches_actual?(expected, actual)
-
expected === actual
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Matchers
-
1
module BuiltIn
-
1
class Eq < BaseMatcher
-
1
def match(expected, actual)
-
6
actual == expected
-
end
-
-
1
def failure_message_for_should
-
"\nexpected: #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using ==)\n"
-
end
-
-
1
def failure_message_for_should_not
-
"\nexpected: value != #{expected.inspect}\n got: #{actual.inspect}\n\n(compared using ==)\n"
-
end
-
-
1
def diffable?; true; end
-
end
-
end
-
end
-
end
-
-
1
module RSpec
-
1
module Matchers
-
1
module BuiltIn
-
1
class Match < BaseMatcher
-
-
1
def match(expected, actual)
-
1
actual.match expected
-
end
-
end
-
end
-
end
-
end
-
1
require 'rspec/mocks/framework'
-
1
require 'rspec/mocks/version'
-
1
require 'rspec/mocks/example_methods'
-
-
1
module RSpec
-
1
module Mocks
-
1
class << self
-
1
attr_accessor :space
-
-
1
def setup(host)
-
27
add_extensions unless extensions_added?
-
54
(class << host; self; end).class_eval do
-
27
include RSpec::Mocks::ExampleMethods
-
end
-
27
self.space ||= RSpec::Mocks::Space.new
-
end
-
-
1
def verify
-
27
space.verify_all
-
end
-
-
1
def teardown
-
27
space.reset_all
-
end
-
-
1
def configuration
-
@configuration ||= Configuration.new
-
end
-
-
# @api private
-
# Used internally by RSpec to display custom deprecation warnings. This
-
# is also defined in rspec-core, but we can't assume it's loaded since
-
# rspec-expectations should be usable w/o rspec-core.
-
1
def warn_deprecation(message)
-
warn(message)
-
end
-
-
# @api private
-
1
KERNEL_METHOD_METHOD = ::Kernel.instance_method(:method)
-
-
# @api private
-
# Used internally to get a method handle for a particular object
-
# and method name.
-
#
-
# Includes handling for a few special cases:
-
#
-
# - Objects that redefine #method (e.g. an HTTPRequest struct)
-
# - BasicObject subclasses that mixin a Kernel dup (e.g. SimpleDelegator)
-
1
def method_handle_for(object, method_name)
-
if ::Kernel === object
-
KERNEL_METHOD_METHOD.bind(object).call(method_name)
-
else
-
object.method(method_name)
-
end
-
end
-
-
1
private
-
-
1
def add_extensions
-
2
method_host.class_eval { include RSpec::Mocks::Methods }
-
2
Class.class_eval { include RSpec::Mocks::AnyInstance }
-
1
$_rspec_mocks_extensions_added = true
-
end
-
-
1
def extensions_added?
-
27
defined?($_rspec_mocks_extensions_added)
-
end
-
-
1
def method_host
-
# On 1.8.7, Object.ancestors.last == Kernel but
-
# things blow up if we include `RSpec::Mocks::Methods`
-
# into Kernel...not sure why.
-
1
return Object unless defined?(::BasicObject)
-
-
# MacRuby has BasicObject but it's not the root class.
-
1
return Object unless Object.ancestors.last == ::BasicObject
-
-
1
::BasicObject
-
end
-
end
-
end
-
end
-
1
require 'rspec/mocks/any_instance/chain'
-
1
require 'rspec/mocks/any_instance/stub_chain'
-
1
require 'rspec/mocks/any_instance/stub_chain_chain'
-
1
require 'rspec/mocks/any_instance/expectation_chain'
-
1
require 'rspec/mocks/any_instance/message_chains'
-
1
require 'rspec/mocks/any_instance/recorder'
-
-
1
module RSpec
-
1
module Mocks
-
1
module AnyInstance
-
# Used to set stubs and message expectations on any instance of a given
-
# class. Returns a [Recorder](Recorder), which records messages like
-
# `stub` and `should_receive` for later playback on instances of the
-
# class.
-
#
-
# @example
-
#
-
# Car.any_instance.should_receive(:go)
-
# race = Race.new
-
# race.cars << Car.new
-
# race.go # assuming this delegates to all of its cars
-
# # this example would pass
-
#
-
# Account.any_instance.stub(:balance) { Money.new(:USD, 25) }
-
# Account.new.balance # => Money.new(:USD, 25))
-
#
-
# @return [Recorder]
-
1
def any_instance
-
RSpec::Mocks::space.add(self)
-
modify_dup_to_remove_mock_proxy_when_invoked
-
__recorder
-
end
-
-
# @private
-
1
def rspec_verify
-
__recorder.verify
-
super
-
ensure
-
__recorder.stop_all_observation!
-
restore_dup
-
@__recorder = nil
-
end
-
-
# @private
-
1
def rspec_reset
-
restore_dup
-
__mock_proxy.reset
-
end
-
-
# @private
-
1
def __recorder
-
@__recorder ||= AnyInstance::Recorder.new(self)
-
end
-
-
1
private
-
1
def modify_dup_to_remove_mock_proxy_when_invoked
-
if method_defined?(:dup) and !method_defined?(:__rspec_original_dup)
-
class_eval do
-
def __rspec_dup(*arguments, &block)
-
__remove_mock_proxy
-
__rspec_original_dup(*arguments, &block)
-
end
-
-
alias_method :__rspec_original_dup, :dup
-
alias_method :dup, :__rspec_dup
-
end
-
end
-
end
-
-
1
def restore_dup
-
if method_defined?(:__rspec_original_dup)
-
class_eval do
-
alias_method :dup, :__rspec_original_dup
-
remove_method :__rspec_original_dup
-
remove_method :__rspec_dup
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
1
module AnyInstance
-
1
class Chain
-
1
class << self
-
1
private
-
-
# @macro [attach] record
-
# @method $1(*args, &block)
-
# Records the `$1` message for playback against an instance that
-
# invokes a method stubbed or mocked using `any_instance`.
-
#
-
# @see RSpec::Mocks::MessageExpectation#$1
-
#
-
1
def record(method_name)
-
14
class_eval(<<-EOM, __FILE__, __LINE__ + 1)
-
def #{method_name}(*args, &block)
-
record(:#{method_name}, *args, &block)
-
end
-
EOM
-
end
-
end
-
-
1
record :and_return
-
1
record :and_raise
-
1
record :and_throw
-
1
record :and_yield
-
1
record :and_call_original
-
1
record :with
-
1
record :once
-
1
record :twice
-
1
record :any_number_of_times
-
1
record :exactly
-
1
record :times
-
1
record :never
-
1
record :at_least
-
1
record :at_most
-
-
# @private
-
1
def playback!(instance)
-
messages.inject(instance) do |_instance, message|
-
_instance.__send__(*message.first, &message.last)
-
end
-
end
-
-
# @private
-
1
def constrained_to_any_of?(*constraints)
-
constraints.any? do |constraint|
-
messages.any? do |message|
-
message.first.first == constraint
-
end
-
end
-
end
-
-
# @private
-
1
def expectation_fulfilled!
-
@expectation_fulfilled = true
-
end
-
-
1
private
-
-
1
def messages
-
@messages ||= []
-
end
-
-
1
def last_message
-
messages.last.first.first unless messages.empty?
-
end
-
-
1
def record(rspec_method_name, *args, &block)
-
verify_invocation_order(rspec_method_name, *args, &block)
-
messages << [args.unshift(rspec_method_name), block]
-
self
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
1
module AnyInstance
-
# @api private
-
1
class ExpectationChain < Chain
-
1
def expectation_fulfilled?
-
@expectation_fulfilled || constrained_to_any_of?(:never, :any_number_of_times)
-
end
-
-
1
def initialize(*args, &block)
-
record(*args, &block)
-
@expectation_fulfilled = false
-
end
-
-
1
private
-
1
def verify_invocation_order(rspec_method_name, *args, &block)
-
end
-
end
-
-
# @api private
-
1
class PositiveExpectationChain < ExpectationChain
-
1
def initialize(*args, &block)
-
super(:should_receive, *args, &block)
-
end
-
-
1
private
-
-
1
def invocation_order
-
@invocation_order ||= {
-
:should_receive => [nil],
-
:with => [:should_receive],
-
:and_return => [:with, :should_receive],
-
:and_raise => [:with, :should_receive]
-
}
-
end
-
end
-
-
# @api private
-
1
class NegativeExpectationChain < ExpectationChain
-
1
def initialize(*args, &block)
-
super(:should_not_receive, *args, &block)
-
end
-
-
# `should_not_receive` causes a failure at the point in time the
-
# message is wrongly received, rather than during `rspec_verify`
-
# at the end of an example. Thus, we should always consider a
-
# negative expectation fulfilled for the purposes of end-of-example
-
# verification (which is where this is used).
-
1
def expectation_fulfilled?
-
true
-
end
-
-
1
private
-
-
1
def invocation_order
-
@invocation_order ||= {
-
:should_not_receive => [nil],
-
:with => [:should_receive],
-
:and_return => [:with, :should_receive],
-
:and_raise => [:with, :should_receive]
-
}
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
1
module AnyInstance
-
# @private
-
1
class MessageChains < Hash
-
1
def initialize
-
super {|h,k| h[k] = []}
-
end
-
-
# @private
-
1
def add(method_name, chain)
-
self[method_name] << chain
-
chain
-
end
-
-
# @private
-
1
def remove_stub_chains_for!(method_name)
-
self[method_name].reject! {|chain| chain.is_a?(StubChain)}
-
end
-
-
# @private
-
1
def has_expectation?(method_name)
-
self[method_name].find {|chain| chain.is_a?(ExpectationChain)}
-
end
-
-
# @private
-
1
def all_expectations_fulfilled?
-
all? {|method_name, chains| chains.all? {|chain| chain.expectation_fulfilled?}}
-
end
-
-
# @private
-
1
def unfulfilled_expectations
-
map do |method_name, chains|
-
method_name.to_s if chains.last.is_a?(ExpectationChain) unless chains.last.expectation_fulfilled?
-
end.compact
-
end
-
-
# @private
-
1
def received_expected_message!(method_name)
-
self[method_name].each {|chain| chain.expectation_fulfilled!}
-
end
-
-
# @private
-
1
def playback!(instance, method_name)
-
raise_if_second_instance_to_receive_message(instance)
-
self[method_name].each {|chain| chain.playback!(instance)}
-
end
-
-
1
private
-
-
1
def raise_if_second_instance_to_receive_message(instance)
-
@instance_with_expectation ||= instance if instance.is_a?(ExpectationChain)
-
if instance.is_a?(ExpectationChain) && !@instance_with_expectation.equal?(instance)
-
raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{unfulfilled_expectations.sort.join(', ')}"
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
1
module AnyInstance
-
# Given a class `TheClass`, `TheClass.any_instance` returns a `Recorder`,
-
# which records stubs and message expectations for later playback on
-
# instances of `TheClass`.
-
#
-
# Further constraints are stored in instances of [Chain](Chain).
-
#
-
# @see AnyInstance
-
# @see Chain
-
1
class Recorder
-
# @private
-
1
attr_reader :message_chains
-
-
1
def initialize(klass)
-
@message_chains = MessageChains.new
-
@observed_methods = []
-
@played_methods = {}
-
@klass = klass
-
@expectation_set = false
-
end
-
-
# Initializes the recording a stub to be played back against any
-
# instance of this object that invokes the submitted method.
-
#
-
# @see Methods#stub
-
1
def stub(method_name_or_method_map, &block)
-
if method_name_or_method_map.is_a?(Hash)
-
method_name_or_method_map.each do |method_name, return_value|
-
stub(method_name).and_return(return_value)
-
end
-
else
-
observe!(method_name_or_method_map)
-
message_chains.add(method_name_or_method_map, StubChain.new(method_name_or_method_map, &block))
-
end
-
end
-
-
# Initializes the recording a stub chain to be played back against any
-
# instance of this object that invokes the method matching the first
-
# argument.
-
#
-
# @see Methods#stub_chain
-
1
def stub_chain(*method_names_and_optional_return_values, &block)
-
normalize_chain(*method_names_and_optional_return_values) do |method_name, args|
-
observe!(method_name)
-
message_chains.add(method_name, StubChainChain.new(*args, &block))
-
end
-
end
-
-
# Initializes the recording a message expectation to be played back
-
# against any instance of this object that invokes the submitted
-
# method.
-
#
-
# @see Methods#should_receive
-
1
def should_receive(method_name, &block)
-
@expectation_set = true
-
observe!(method_name)
-
message_chains.add(method_name, PositiveExpectationChain.new(method_name, &block))
-
end
-
-
1
def should_not_receive(method_name, &block)
-
observe!(method_name)
-
message_chains.add(method_name, NegativeExpectationChain.new(method_name, &block))
-
end
-
-
# Removes any previously recorded stubs, stub_chains or message
-
# expectations that use `method_name`.
-
#
-
# @see Methods#unstub
-
1
def unstub(method_name)
-
unless @observed_methods.include?(method_name.to_sym)
-
raise RSpec::Mocks::MockExpectationError, "The method `#{method_name}` was not stubbed or was already unstubbed"
-
end
-
message_chains.remove_stub_chains_for!(method_name)
-
stop_observing!(method_name) unless message_chains.has_expectation?(method_name)
-
end
-
-
# @api private
-
#
-
# Used internally to verify that message expectations have been
-
# fulfilled.
-
1
def verify
-
if @expectation_set && !message_chains.all_expectations_fulfilled?
-
raise RSpec::Mocks::MockExpectationError, "Exactly one instance should have received the following message(s) but didn't: #{message_chains.unfulfilled_expectations.sort.join(', ')}"
-
end
-
end
-
-
# @private
-
1
def stub!(*)
-
raise "stub! is not supported on any_instance. Use stub instead."
-
end
-
-
# @private
-
1
def unstub!(*)
-
raise "unstub! is not supported on any_instance. Use unstub instead."
-
end
-
-
# @private
-
1
def stop_all_observation!
-
@observed_methods.each {|method_name| restore_method!(method_name)}
-
end
-
-
# @private
-
1
def playback!(instance, method_name)
-
RSpec::Mocks::space.add(instance)
-
message_chains.playback!(instance, method_name)
-
@played_methods[method_name] = instance
-
received_expected_message!(method_name) if message_chains.has_expectation?(method_name)
-
end
-
-
# @private
-
1
def instance_that_received(method_name)
-
@played_methods[method_name]
-
end
-
-
1
def build_alias_method_name(method_name)
-
"__#{method_name}_without_any_instance__"
-
end
-
-
1
def already_observing?(method_name)
-
@observed_methods.include?(method_name)
-
end
-
-
1
private
-
-
1
def normalize_chain(*args)
-
args.shift.to_s.split('.').map {|s| s.to_sym}.reverse.each {|a| args.unshift a}
-
yield args.first, args
-
end
-
-
1
def received_expected_message!(method_name)
-
message_chains.received_expected_message!(method_name)
-
restore_method!(method_name)
-
mark_invoked!(method_name)
-
end
-
-
1
def restore_method!(method_name)
-
if public_protected_or_private_method_defined?(build_alias_method_name(method_name))
-
restore_original_method!(method_name)
-
else
-
remove_dummy_method!(method_name)
-
end
-
end
-
-
1
def restore_original_method!(method_name)
-
alias_method_name = build_alias_method_name(method_name)
-
@klass.class_eval do
-
remove_method method_name
-
alias_method method_name, alias_method_name
-
remove_method alias_method_name
-
end
-
end
-
-
1
def remove_dummy_method!(method_name)
-
@klass.class_eval do
-
remove_method method_name
-
end
-
end
-
-
1
def backup_method!(method_name)
-
alias_method_name = build_alias_method_name(method_name)
-
@klass.class_eval do
-
alias_method alias_method_name, method_name
-
end if public_protected_or_private_method_defined?(method_name)
-
end
-
-
1
def public_protected_or_private_method_defined?(method_name)
-
@klass.method_defined?(method_name) || @klass.private_method_defined?(method_name)
-
end
-
-
1
def stop_observing!(method_name)
-
restore_method!(method_name)
-
@observed_methods.delete(method_name)
-
end
-
-
1
def observe!(method_name)
-
stop_observing!(method_name) if already_observing?(method_name)
-
@observed_methods << method_name
-
backup_method!(method_name)
-
@klass.class_eval(<<-EOM, __FILE__, __LINE__ + 1)
-
def #{method_name}(*args, &blk)
-
klass = ::RSpec::Mocks.method_handle_for(self, :#{method_name}).owner
-
klass.__recorder.playback!(self, :#{method_name})
-
self.__send__(:#{method_name}, *args, &blk)
-
end
-
EOM
-
end
-
-
1
def mark_invoked!(method_name)
-
backup_method!(method_name)
-
@klass.class_eval(<<-EOM, __FILE__, __LINE__ + 1)
-
def #{method_name}(*args, &blk)
-
method_name = :#{method_name}
-
klass = ::RSpec::Mocks.method_handle_for(self, :#{method_name}).owner
-
invoked_instance = klass.__recorder.instance_that_received(method_name)
-
raise RSpec::Mocks::MockExpectationError, "The message '#{method_name}' was received by \#{self.inspect} but has already been received by \#{invoked_instance}"
-
end
-
EOM
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
1
module AnyInstance
-
# @private
-
1
class StubChain < Chain
-
-
# @private
-
1
def initialize(*args, &block)
-
record(:stub, *args, &block)
-
end
-
-
# @private
-
1
def expectation_fulfilled?
-
true
-
end
-
-
1
private
-
-
1
def invocation_order
-
@invocation_order ||= {
-
:stub => [nil],
-
:with => [:stub],
-
:and_return => [:with, :stub],
-
:and_raise => [:with, :stub],
-
:and_yield => [:with, :stub]
-
}
-
end
-
-
1
def verify_invocation_order(rspec_method_name, *args, &block)
-
unless invocation_order[rspec_method_name].include?(last_message)
-
raise(NoMethodError, "Undefined method #{rspec_method_name}")
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
1
module AnyInstance
-
# @private
-
1
class StubChainChain < StubChain
-
-
# @private
-
1
def initialize(*args, &block)
-
record(:stub_chain, *args, &block)
-
end
-
-
1
private
-
-
1
def invocation_order
-
@invocation_order ||= {
-
:stub_chain => [nil],
-
:and_return => [:stub_chain],
-
:and_raise => [:stub_chain],
-
:and_yield => [:stub_chain]
-
}
-
end
-
end
-
end
-
end
-
end
-
1
require 'rspec/mocks/argument_matchers'
-
-
1
module RSpec
-
1
module Mocks
-
# Wrapper for matching arguments against a list of expected values. Used by
-
# the `with` method on a `MessageExpectation`:
-
#
-
# object.should_receive(:message).with(:a, 'b', 3)
-
# object.message(:a, 'b', 3)
-
#
-
# Values passed to `with` can be literal values or argument matchers that
-
# match against the real objects .e.g.
-
#
-
# object.should_receive(:message).with(hash_including(:a => 'b'))
-
#
-
# Can also be used directly to match the contents of any `Array`. This
-
# enables 3rd party mocking libs to take advantage of rspec's argument
-
# matching without using the rest of rspec-mocks.
-
#
-
# require 'rspec/mocks/argument_list_matcher'
-
# include RSpec::Mocks::ArgumentMatchers
-
#
-
# arg_list_matcher = RSpec::Mocks::ArgumentListMatcher.new(123, hash_including(:a => 'b'))
-
# arg_list_matcher.args_match?(123, :a => 'b')
-
#
-
# @see ArgumentMatchers
-
1
class ArgumentListMatcher
-
# @private
-
1
attr_reader :expected_args
-
-
# @api public
-
# @param [Array] *expected_args a list of expected literals and/or argument matchers
-
# @param [Block] block a block with arity matching the expected
-
#
-
# Initializes an `ArgumentListMatcher` with a collection of literal
-
# values and/or argument matchers, or a block that handles the evaluation
-
# for you.
-
#
-
# @see ArgumentMatchers
-
# @see #args_match?
-
1
def initialize(*expected_args, &block)
-
@expected_args = expected_args
-
@block = expected_args.empty? ? block : nil
-
@match_any_args = false
-
@matchers = nil
-
-
case expected_args.first
-
when ArgumentMatchers::AnyArgsMatcher
-
@match_any_args = true
-
when ArgumentMatchers::NoArgsMatcher
-
@matchers = []
-
else
-
@matchers = expected_args.collect {|arg| matcher_for(arg)}
-
end
-
end
-
-
# @api public
-
# @param [Array] *args
-
#
-
# Matches each element in the `expected_args` against the element in the same
-
# position of the arguments passed to `new`.
-
#
-
# @see #initialize
-
1
def args_match?(*args)
-
match_any_args? || block_passes?(*args) || matchers_match?(*args)
-
end
-
-
1
private
-
-
1
def matcher_for(arg)
-
return ArgumentMatchers::MatcherMatcher.new(arg) if is_matcher?(arg)
-
return ArgumentMatchers::RegexpMatcher.new(arg) if arg.is_a?(Regexp)
-
return ArgumentMatchers::EqualityProxy.new(arg)
-
end
-
-
1
def is_matcher?(obj)
-
!obj.null_object? & obj.respond_to?(:matches?) & [:failure_message_for_should, :failure_message].any? { |m| obj.respond_to?(m) }
-
end
-
-
1
def block_passes?(*args)
-
@block.call(*args) if @block
-
end
-
-
1
def matchers_match?(*args)
-
@matchers == args
-
end
-
-
1
def match_any_args?
-
@match_any_args
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
-
# ArgumentMatchers are placeholders that you can include in message
-
# expectations to match arguments against a broader check than simple
-
# equality.
-
#
-
# With the exception of `any_args` and `no_args`, they all match against
-
# the arg in same position in the argument list.
-
#
-
# @see ArgumentListMatcher
-
1
module ArgumentMatchers
-
-
1
class AnyArgsMatcher
-
1
def description
-
"any args"
-
end
-
end
-
-
1
class AnyArgMatcher
-
1
def initialize(ignore)
-
end
-
-
1
def ==(other)
-
true
-
end
-
end
-
-
1
class NoArgsMatcher
-
1
def description
-
"no args"
-
end
-
end
-
-
1
class RegexpMatcher
-
1
def initialize(regexp)
-
@regexp = regexp
-
end
-
-
1
def ==(value)
-
Regexp === value ? value == @regexp : value =~ @regexp
-
end
-
end
-
-
1
class BooleanMatcher
-
1
def initialize(ignore)
-
end
-
-
1
def ==(value)
-
[true,false].include?(value)
-
end
-
end
-
-
1
class HashIncludingMatcher
-
1
def initialize(expected)
-
@expected = expected
-
end
-
-
1
def ==(actual)
-
@expected.all? {|k,v| actual.has_key?(k) && v == actual[k]}
-
rescue NoMethodError
-
false
-
end
-
-
1
def description
-
"hash_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
-
end
-
end
-
-
1
class HashExcludingMatcher
-
1
def initialize(expected)
-
@expected = expected
-
end
-
-
1
def ==(actual)
-
@expected.none? {|k,v| actual.has_key?(k) && v == actual[k]}
-
rescue NoMethodError
-
false
-
end
-
-
1
def description
-
"hash_not_including(#{@expected.inspect.sub(/^\{/,"").sub(/\}$/,"")})"
-
end
-
end
-
-
1
class DuckTypeMatcher
-
1
def initialize(*methods_to_respond_to)
-
@methods_to_respond_to = methods_to_respond_to
-
end
-
-
1
def ==(value)
-
@methods_to_respond_to.all? {|message| value.respond_to?(message)}
-
end
-
end
-
-
1
class MatcherMatcher
-
1
def initialize(matcher)
-
@matcher = matcher
-
end
-
-
1
def ==(value)
-
@matcher.matches?(value)
-
end
-
end
-
-
1
class EqualityProxy
-
1
def initialize(given)
-
@given = given
-
end
-
-
1
def ==(expected)
-
@given == expected
-
end
-
end
-
-
1
class InstanceOf
-
1
def initialize(klass)
-
@klass = klass
-
end
-
-
1
def ==(actual)
-
actual.instance_of?(@klass)
-
end
-
end
-
-
1
class KindOf
-
1
def initialize(klass)
-
@klass = klass
-
end
-
-
1
def ==(actual)
-
actual.kind_of?(@klass)
-
end
-
end
-
-
# Matches any args at all. Supports a more explicit variation of
-
# `object.should_receive(:message)`
-
#
-
# @example
-
#
-
# object.should_receive(:message).with(any_args)
-
1
def any_args
-
AnyArgsMatcher.new
-
end
-
-
# Matches any argument at all.
-
#
-
# @example
-
#
-
# object.should_receive(:message).with(anything)
-
1
def anything
-
AnyArgMatcher.new(nil)
-
end
-
-
# Matches no arguments.
-
#
-
# @example
-
#
-
# object.should_receive(:message).with(no_args)
-
1
def no_args
-
NoArgsMatcher.new
-
end
-
-
# Matches if the actual argument responds to the specified messages.
-
#
-
# @example
-
#
-
# object.should_receive(:message).with(duck_type(:hello))
-
# object.should_receive(:message).with(duck_type(:hello, :goodbye))
-
1
def duck_type(*args)
-
DuckTypeMatcher.new(*args)
-
end
-
-
# Matches a boolean value.
-
#
-
# @example
-
#
-
# object.should_receive(:message).with(boolean())
-
1
def boolean
-
BooleanMatcher.new(nil)
-
end
-
-
# Matches a hash that includes the specified key(s) or key/value pairs.
-
# Ignores any additional keys.
-
#
-
# @example
-
#
-
# object.should_receive(:message).with(hash_including(:key => val))
-
# object.should_receive(:message).with(hash_including(:key))
-
# object.should_receive(:message).with(hash_including(:key, :key2 => val2))
-
1
def hash_including(*args)
-
HashIncludingMatcher.new(anythingize_lonely_keys(*args))
-
end
-
-
# Matches a hash that doesn't include the specified key(s) or key/value.
-
#
-
# @example
-
#
-
# object.should_receive(:message).with(hash_excluding(:key => val))
-
# object.should_receive(:message).with(hash_excluding(:key))
-
# object.should_receive(:message).with(hash_excluding(:key, :key2 => :val2))
-
1
def hash_excluding(*args)
-
HashExcludingMatcher.new(anythingize_lonely_keys(*args))
-
end
-
-
1
alias_method :hash_not_including, :hash_excluding
-
-
# Matches if `arg.instance_of?(klass)`
-
#
-
# @example
-
#
-
# object.should_receive(:message).with(instance_of(Thing))
-
1
def instance_of(klass)
-
InstanceOf.new(klass)
-
end
-
-
1
alias_method :an_instance_of, :instance_of
-
-
# Matches if `arg.kind_of?(klass)`
-
# @example
-
#
-
# object.should_receive(:message).with(kind_of(Thing))
-
1
def kind_of(klass)
-
KindOf.new(klass)
-
end
-
-
1
alias_method :a_kind_of, :kind_of
-
-
1
private
-
-
1
def anythingize_lonely_keys(*args)
-
hash = args.last.class == Hash ? args.delete_at(-1) : {}
-
args.each { | arg | hash[arg] = anything }
-
hash
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
# Provides configuration options for rspec-mocks.
-
1
class Configuration
-
# Adds `stub` and `should_receive` to the given
-
# modules or classes. This is usually only necessary
-
# if you application uses some proxy classes that
-
# "strip themselves down" to a bare minimum set of
-
# methods and remove `stub` and `should_receive` in
-
# the process.
-
#
-
# @example
-
#
-
# RSpec.configure do |rspec|
-
# rspec.mock_with :rspec do |mocks|
-
# mocks.add_stub_and_should_receive_to Delegator
-
# end
-
# end
-
#
-
1
def add_stub_and_should_receive_to(*modules)
-
modules.each do |mod|
-
mod.__send__(:include, RSpec::Mocks::Methods)
-
end
-
end
-
end
-
end
-
end
-
-
1
module RSpec
-
1
module Mocks
-
# @private
-
1
class ErrorGenerator
-
1
attr_writer :opts
-
-
1
def initialize(target, name, options={})
-
@declared_as = options[:__declared_as] || 'Mock'
-
@target = target
-
@name = name
-
end
-
-
# @private
-
1
def opts
-
@opts ||= {}
-
end
-
-
# @private
-
1
def raise_unexpected_message_error(message, *args)
-
__raise "#{intro} received unexpected message :#{message}#{arg_message(*args)}"
-
end
-
-
# @private
-
1
def raise_unexpected_message_args_error(expectation, *args)
-
expected_args = format_args(*expectation.expected_args)
-
actual_args = format_args(*args)
-
__raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}"
-
end
-
-
# @private
-
1
def raise_missing_default_stub_error(expectation, *args)
-
expected_args = format_args(*expectation.expected_args)
-
actual_args = format_args(*args)
-
__raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}\n Please stub a default value first if message might be received with other args as well. \n"
-
end
-
-
# @private
-
1
def raise_similar_message_args_error(expectation, *args_for_multiple_calls)
-
expected_args = format_args(*expectation.expected_args)
-
actual_args = args_for_multiple_calls.collect {|a| format_args(*a)}.join(", ")
-
__raise "#{intro} received #{expectation.message.inspect} with unexpected arguments\n expected: #{expected_args}\n got: #{actual_args}"
-
end
-
-
# @private
-
1
def raise_expectation_error(message, expected_received_count, actual_received_count, *args)
-
__raise "(#{intro}).#{message}#{format_args(*args)}\n expected: #{count_message(expected_received_count)}\n received: #{count_message(actual_received_count)}"
-
end
-
-
# @private
-
1
def raise_out_of_order_error(message)
-
__raise "#{intro} received :#{message} out of order"
-
end
-
-
# @private
-
1
def raise_block_failed_error(message, detail)
-
__raise "#{intro} received :#{message} but passed block failed with: #{detail}"
-
end
-
-
# @private
-
1
def raise_missing_block_error(args_to_yield)
-
__raise "#{intro} asked to yield |#{arg_list(*args_to_yield)}| but no block was passed"
-
end
-
-
# @private
-
1
def raise_wrong_arity_error(args_to_yield, arity)
-
__raise "#{intro} yielded |#{arg_list(*args_to_yield)}| to block with arity of #{arity}"
-
end
-
-
# @private
-
1
def raise_only_valid_on_a_partial_mock(method)
-
__raise "#{intro} is a pure mock object. `#{method}` is only " +
-
"available on a partial mock object."
-
end
-
-
1
private
-
-
1
def intro
-
if @name
-
"#{@declared_as} #{@name.inspect}"
-
elsif TestDouble === @target
-
@declared_as
-
elsif Class === @target
-
"<#{@target.inspect} (class)>"
-
elsif @target
-
@target
-
else
-
"nil"
-
end
-
end
-
-
1
def __raise(message)
-
message = opts[:message] unless opts[:message].nil?
-
Kernel::raise(RSpec::Mocks::MockExpectationError, message)
-
end
-
-
1
def arg_message(*args)
-
" with " + format_args(*args)
-
end
-
-
1
def format_args(*args)
-
args.empty? ? "(no args)" : "(" + arg_list(*args) + ")"
-
end
-
-
1
def arg_list(*args)
-
args.collect {|arg| arg.respond_to?(:description) ? arg.description : arg.inspect}.join(", ")
-
end
-
-
1
def count_message(count)
-
return "at least #{pretty_print(count.abs)}" if count < 0
-
return pretty_print(count)
-
end
-
-
1
def pretty_print(count)
-
"#{count} time#{count == 1 ? '' : 's'}"
-
end
-
-
end
-
end
-
end
-
-
1
module RSpec
-
1
module Mocks
-
# @private
-
1
class MockExpectationError < Exception
-
end
-
-
# @private
-
1
class AmbiguousReturnError < StandardError
-
end
-
end
-
end
-
-
1
module RSpec
-
1
module Mocks
-
1
module ExampleMethods
-
1
include RSpec::Mocks::ArgumentMatchers
-
-
# @overload double()
-
# @overload double(name)
-
# @overload double(stubs)
-
# @overload double(name, stubs)
-
# @param name [String/Symbol] (optional) used in
-
# clarify intent
-
# @param stubs (Hash) (optional) hash of method/return-value pairs
-
# @return (Mock)
-
#
-
# Constructs an instance of [RSpec::Mocks::Mock](RSpec::Mocks::Mock) configured
-
# with an optional name, used for reporting in failure messages, and an optional
-
# hash of method/return-value pairs.
-
#
-
# @example
-
#
-
# book = double("book", :title => "The RSpec Book")
-
# book.title #=> "The RSpec Book"
-
#
-
# card = double("card", :suit => "Spades", :rank => "A")
-
# card.suit #=> "Spades"
-
# card.rank #=> "A"
-
#
-
# @see #mock
-
# @see #stub
-
1
def double(*args)
-
declare_double('Double', *args)
-
end
-
-
# Effectively an alias for [double](#double-instance_method).
-
1
def mock(*args)
-
declare_double('Mock', *args)
-
end
-
-
# Effectively an alias for [double](#double-instance_method).
-
1
def stub(*args)
-
declare_double('Stub', *args)
-
end
-
-
# Disables warning messages about expectations being set on nil.
-
#
-
# By default warning messages are issued when expectations are set on
-
# nil. This is to prevent false-positives and to catch potential bugs
-
# early on.
-
1
def allow_message_expectations_on_nil
-
Proxy.allow_message_expectations_on_nil
-
end
-
-
# Stubs the named constant with the given value.
-
# Like method stubs, the constant will be restored
-
# to its original value (or lack of one, if it was
-
# undefined) when the example completes.
-
#
-
# @param constant_name [String] The fully qualified name of the constant. The current
-
# constant scoping at the point of call is not considered.
-
# @param value [Object] The value to make the constant refer to. When the
-
# example completes, the constant will be restored to its prior state.
-
# @param options [Hash] Stubbing options.
-
# @option options :transfer_nested_constants [Boolean, Array<Symbol>] Determines
-
# what nested constants, if any, will be transferred from the original value
-
# of the constant to the new value of the constant. This only works if both
-
# the original and new values are modules (or classes).
-
# @return [Object] the stubbed value of the constant
-
#
-
# @example
-
#
-
# stub_const("MyClass", Class.new) # => Replaces (or defines) MyClass with a new class object.
-
# stub_const("SomeModel::PER_PAGE", 5) # => Sets SomeModel::PER_PAGE to 5.
-
#
-
# class CardDeck
-
# SUITS = [:Spades, :Diamonds, :Clubs, :Hearts]
-
# NUM_CARDS = 52
-
# end
-
#
-
# stub_const("CardDeck", Class.new)
-
# CardDeck::SUITS # => uninitialized constant error
-
# CardDeck::NUM_CARDS # => uninitialized constant error
-
#
-
# stub_const("CardDeck", Class.new, :transfer_nested_constants => true)
-
# CardDeck::SUITS # => our suits array
-
# CardDeck::NUM_CARDS # => 52
-
#
-
# stub_const("CardDeck", Class.new, :transfer_nested_constants => [:SUITS])
-
# CardDeck::SUITS # => our suits array
-
# CardDeck::NUM_CARDS # => uninitialized constant error
-
1
def stub_const(constant_name, value, options = {})
-
ConstantMutator.stub(constant_name, value, options)
-
end
-
-
# Hides the named constant with the given value. The constant will be
-
# undefined for the duration of the test.
-
#
-
# Like method stubs, the constant will be restored to its original value
-
# when the example completes.
-
#
-
# @param constant_name [String] The fully qualified name of the constant.
-
# The current constant scoping at the point of call is not considered.
-
#
-
# @example
-
#
-
# hide_const("MyClass") # => MyClass is now an undefined constant
-
1
def hide_const(constant_name)
-
ConstantMutator.hide(constant_name)
-
end
-
-
1
private
-
-
1
def declare_double(declared_as, *args)
-
args << {} unless Hash === args.last
-
args.last[:__declared_as] = declared_as
-
RSpec::Mocks::Mock.new(*args)
-
end
-
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
# @private
-
1
module InstanceExec
-
1
unless respond_to?(:instance_exec)
-
# @private
-
#
-
# based on Bounded Spec InstanceExec (Mauricio Fernandez)
-
# http://eigenclass.org/hiki/bounded+space+instance_exec
-
# - uses singleton_class of matcher instead of global
-
# InstanceExecHelper module
-
# - this keeps it scoped to this class only, which is the
-
# only place we need it
-
# - only necessary for ruby 1.8.6
-
def instance_exec(*args, &block)
-
singleton_class = (class << self; self; end)
-
begin
-
orig_critical, Thread.critical = Thread.critical, true
-
n = 0
-
n += 1 while respond_to?(method_name="__instance_exec#{n}")
-
singleton_class.module_eval{ define_method(method_name, &block) }
-
ensure
-
Thread.critical = orig_critical
-
end
-
begin
-
return send(method_name, *args)
-
ensure
-
singleton_class.module_eval{ remove_method(method_name) } rescue nil
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module Marshal
-
1
class << self
-
1
def dump_with_mocks(*args)
-
object = args.shift
-
return dump_without_mocks(*args.unshift(object)) unless object.instance_variable_defined?(:@mock_proxy)
-
-
mp = object.instance_variable_get(:@mock_proxy)
-
return dump_without_mocks(*args.unshift(object)) unless mp.is_a?(::RSpec::Mocks::Proxy)
-
-
object.__send__(:remove_instance_variable, :@mock_proxy)
-
-
begin
-
dump_without_mocks(*args.unshift(object.dup))
-
ensure
-
object.instance_variable_set(:@mock_proxy,mp)
-
end
-
end
-
-
1
alias_method :dump_without_mocks, :dump
-
1
undef_method :dump
-
1
alias_method :dump, :dump_with_mocks
-
end
-
end
-
1
if defined?(Psych) && Psych.respond_to?(:dump)
-
1
module Psych
-
1
class << self
-
1
def dump_with_mocks(object, *args)
-
return dump_without_mocks(object, *args) unless object.instance_variable_defined?(:@mock_proxy)
-
-
mp = object.instance_variable_get(:@mock_proxy)
-
return dump_without_mocks(object, *args) unless mp.is_a?(::RSpec::Mocks::Proxy)
-
-
object.__send__(:remove_instance_variable, :@mock_proxy)
-
-
begin
-
dump_without_mocks(object, *args)
-
ensure
-
object.instance_variable_set(:@mock_proxy, mp)
-
end
-
end
-
-
1
alias_method :dump_without_mocks, :dump
-
1
alias_method :dump, :dump_with_mocks
-
end
-
end
-
end
-
# Require everything except the global extensions of class and object. This
-
# supports wrapping rspec's mocking functionality without invading every
-
# object in the system.
-
-
1
require 'rspec/mocks/configuration'
-
1
require 'rspec/mocks/extensions/instance_exec'
-
1
require 'rspec/mocks/instance_method_stasher'
-
1
require 'rspec/mocks/method_double'
-
1
require 'rspec/mocks/methods'
-
1
require 'rspec/mocks/argument_matchers'
-
1
require 'rspec/mocks/proxy'
-
1
require 'rspec/mocks/test_double'
-
1
require 'rspec/mocks/mock'
-
1
require 'rspec/mocks/argument_list_matcher'
-
1
require 'rspec/mocks/message_expectation'
-
1
require 'rspec/mocks/order_group'
-
1
require 'rspec/mocks/errors'
-
1
require 'rspec/mocks/error_generator'
-
1
require 'rspec/mocks/space'
-
1
require 'rspec/mocks/serialization'
-
1
require 'rspec/mocks/any_instance'
-
1
require 'rspec/mocks/mutate_const'
-
1
module RSpec
-
1
module Mocks
-
# @private
-
1
class InstanceMethodStasher
-
1
def initialize(klass, method)
-
@klass = klass
-
@method = method
-
-
@method_is_stashed = false
-
end
-
-
# @private
-
1
def method_is_stashed?
-
@method_is_stashed
-
end
-
-
# @private
-
1
def stash
-
return if !method_defined_directly_on_klass? || @method_is_stashed
-
-
@klass.__send__(:alias_method, stashed_method_name, @method)
-
@method_is_stashed = true
-
end
-
-
1
private
-
-
# @private
-
1
def method_defined_directly_on_klass?
-
method_defined_on_klass? && method_owned_by_klass?
-
end
-
-
# @private
-
1
def method_defined_on_klass?(klass = @klass)
-
klass.method_defined?(@method) || klass.private_method_defined?(@method)
-
end
-
-
1
if ::UnboundMethod.method_defined?(:owner)
-
# @private
-
1
def method_owned_by_klass?
-
owner = @klass.instance_method(@method).owner
-
# On 1.8 (and some 1.9s -- e.g. rubinius) aliased methods
-
# can report the wrong owner. Example:
-
# class MyClass
-
# class << self
-
# alias alternate_new new
-
# end
-
# end
-
#
-
# MyClass.owner(:alternate_new) returns `Class` on 1.8,
-
# but we need to consider the owner to be `MyClass` because
-
# it is not actually available on `Class` but is on `MyClass`.
-
# Hence, we verify that the owner actually has the method defined.
-
# If the given owner does not have the method defined, we assume
-
# that the method is actually owned by @klass.
-
owner == @klass || !(method_defined_on_klass?(owner))
-
end
-
else
-
# @private
-
def method_owned_by_klass?
-
# On 1.8.6, which does not support Method#owner, we have no choice but
-
# to assume it's defined on the klass even if it may be defined on
-
# a superclass.
-
true
-
end
-
end
-
-
1
public
-
-
# @private
-
1
def stashed_method_name
-
"obfuscated_by_rspec_mocks__#{@method}"
-
end
-
-
# @private
-
1
def restore
-
return unless @method_is_stashed
-
-
@klass.__send__(:alias_method, @method, stashed_method_name)
-
@klass.__send__(:remove_method, stashed_method_name)
-
@method_is_stashed = false
-
end
-
end
-
end
-
end
-
-
1
module RSpec
-
1
module Mocks
-
-
1
class MessageExpectation
-
# @private
-
1
attr_accessor :error_generator, :implementation
-
1
attr_reader :message
-
1
attr_writer :expected_received_count, :expected_from, :argument_list_matcher
-
1
protected :expected_received_count=, :expected_from=, :error_generator, :error_generator=, :implementation=
-
-
# @private
-
1
def initialize(error_generator, expectation_ordering, expected_from, method_double,
-
expected_received_count=1, opts={}, &implementation_block)
-
@error_generator = error_generator
-
@error_generator.opts = opts
-
@expected_from = expected_from
-
@method_double = method_double
-
@message = @method_double.method_name
-
@actual_received_count = 0
-
@expected_received_count = expected_received_count
-
@argument_list_matcher = ArgumentListMatcher.new(ArgumentMatchers::AnyArgsMatcher.new)
-
@order_group = expectation_ordering
-
@at_least = @at_most = @exactly = nil
-
@args_to_yield = []
-
@failed_fast = nil
-
@eval_context = nil
-
-
@implementation = Implementation.new
-
self.inner_implementation_action = implementation_block
-
end
-
-
# @private
-
-
# @private
-
1
def expected_args
-
@argument_list_matcher.expected_args
-
end
-
-
# @overload and_return(value)
-
# @overload and_return(first_value, second_value)
-
# @overload and_return(&block)
-
#
-
# Tells the object to return a value when it receives the message. Given
-
# more than one value, the first value is returned the first time the
-
# message is received, the second value is returned the next time, etc,
-
# etc.
-
#
-
# If the message is received more times than there are values, the last
-
# value is received for every subsequent call.
-
#
-
# The block format is still supported, but is unofficially deprecated in
-
# favor of just passing a block to the stub method.
-
#
-
# @example
-
#
-
# counter.stub(:count).and_return(1)
-
# counter.count # => 1
-
# counter.count # => 1
-
#
-
# counter.stub(:count).and_return(1,2,3)
-
# counter.count # => 1
-
# counter.count # => 2
-
# counter.count # => 3
-
# counter.count # => 3
-
# counter.count # => 3
-
# # etc
-
#
-
# # Supported, but ...
-
# counter.stub(:count).and_return { 1 }
-
# counter.count # => 1
-
#
-
# # ... this is prefered
-
# counter.stub(:count) { 1 }
-
# counter.count # => 1
-
1
def and_return(*values, &implementation)
-
@expected_received_count = [@expected_received_count, values.size].max unless ignoring_args? || (@expected_received_count == 0 and @at_least)
-
-
if implementation
-
# TODO: deprecate `and_return { value }`
-
self.inner_implementation_action = implementation
-
else
-
self.terminal_implementation_action = AndReturnImplementation.new(values)
-
end
-
-
nil
-
end
-
-
# Tells the object to delegate to the original unmodified method
-
# when it receives the message.
-
#
-
# @note This is only available on partial mock objects.
-
#
-
# @example
-
#
-
# counter.should_receive(:increment).and_call_original
-
# original_count = counter.count
-
# counter.increment
-
# expect(counter.count).to eq(original_count + 1)
-
1
def and_call_original
-
if @method_double.object.is_a?(RSpec::Mocks::TestDouble)
-
@error_generator.raise_only_valid_on_a_partial_mock(:and_call_original)
-
else
-
@implementation = AndCallOriginalImplementation.new(@method_double.original_method)
-
end
-
end
-
-
# @overload and_raise
-
# @overload and_raise(ExceptionClass)
-
# @overload and_raise(ExceptionClass, message)
-
# @overload and_raise(exception_instance)
-
#
-
# Tells the object to raise an exception when the message is received.
-
#
-
# @note
-
#
-
# When you pass an exception class, the MessageExpectation will raise
-
# an instance of it, creating it with `exception` and passing `message`
-
# if specified. If the exception class initializer requires more than
-
# one parameters, you must pass in an instance and not the class,
-
# otherwise this method will raise an ArgumentError exception.
-
#
-
# @example
-
#
-
# car.stub(:go).and_raise
-
# car.stub(:go).and_raise(OutOfGas)
-
# car.stub(:go).and_raise(OutOfGas, "At least 2 oz of gas needed to drive")
-
# car.stub(:go).and_raise(OutOfGas.new(2, :oz))
-
1
def and_raise(exception = RuntimeError, message = nil)
-
if exception.respond_to?(:exception)
-
exception = message ? exception.exception(message) : exception.exception
-
end
-
-
self.terminal_implementation_action = Proc.new { raise exception }
-
nil
-
end
-
-
# @overload and_throw(symbol)
-
# @overload and_throw(symbol, object)
-
#
-
# Tells the object to throw a symbol (with the object if that form is
-
# used) when the message is received.
-
#
-
# @example
-
#
-
# car.stub(:go).and_throw(:out_of_gas)
-
# car.stub(:go).and_throw(:out_of_gas, :level => 0.1)
-
1
def and_throw(*args)
-
self.terminal_implementation_action = Proc.new { throw *args }
-
nil
-
end
-
-
# Tells the object to yield one or more args to a block when the message
-
# is received.
-
#
-
# @example
-
#
-
# stream.stub(:open).and_yield(StringIO.new)
-
1
def and_yield(*args, &block)
-
yield @eval_context = Object.new.extend(RSpec::Mocks::InstanceExec) if block
-
@args_to_yield << args
-
self.initial_implementation_action = AndYieldImplementation.new(@args_to_yield, @eval_context, @error_generator)
-
self
-
end
-
-
# @private
-
1
def matches?(message, *args)
-
@message == message && @argument_list_matcher.args_match?(*args)
-
end
-
-
# @private
-
1
def invoke(parent_stub, *args, &block)
-
if (@expected_received_count == 0 && !@at_least) || ((@exactly || @at_most) && (@actual_received_count == @expected_received_count))
-
@actual_received_count += 1
-
@failed_fast = true
-
@error_generator.raise_expectation_error(@message, @expected_received_count, @actual_received_count, *args)
-
end
-
-
@order_group.handle_order_constraint self
-
-
begin
-
if implementation.present?
-
implementation.call(*args, &block)
-
elsif parent_stub
-
parent_stub.invoke(nil, *args, &block)
-
end
-
ensure
-
@actual_received_count += 1
-
end
-
end
-
-
# @private
-
1
def called_max_times?
-
@expected_received_count != :any &&
-
!@at_least &&
-
@expected_received_count > 0 &&
-
@actual_received_count >= @expected_received_count
-
end
-
-
# @private
-
1
def matches_name_but_not_args(message, *args)
-
@message == message and not @argument_list_matcher.args_match?(*args)
-
end
-
-
# @private
-
1
def verify_messages_received
-
generate_error unless expected_messages_received? || failed_fast?
-
rescue RSpec::Mocks::MockExpectationError => error
-
error.backtrace.insert(0, @expected_from)
-
Kernel::raise error
-
end
-
-
# @private
-
1
def expected_messages_received?
-
ignoring_args? || matches_exact_count? || matches_at_least_count? || matches_at_most_count?
-
end
-
-
# @private
-
1
def ignoring_args?
-
@expected_received_count == :any
-
end
-
-
# @private
-
1
def matches_at_least_count?
-
@at_least && @actual_received_count >= @expected_received_count
-
end
-
-
# @private
-
1
def matches_at_most_count?
-
@at_most && @actual_received_count <= @expected_received_count
-
end
-
-
# @private
-
1
def matches_exact_count?
-
@expected_received_count == @actual_received_count
-
end
-
-
# @private
-
1
def similar_messages
-
@similar_messages ||= []
-
end
-
-
# @private
-
1
def advise(*args)
-
similar_messages << args
-
end
-
-
# @private
-
1
def generate_error
-
if similar_messages.empty?
-
@error_generator.raise_expectation_error(@message, @expected_received_count, @actual_received_count, *expected_args)
-
else
-
@error_generator.raise_similar_message_args_error(self, *@similar_messages)
-
end
-
end
-
-
1
def raise_out_of_order_error
-
@error_generator.raise_out_of_order_error @message
-
end
-
-
# Constrains a stub or message expectation to invocations with specific
-
# arguments.
-
#
-
# With a stub, if the message might be received with other args as well,
-
# you should stub a default value first, and then stub or mock the same
-
# message using `with` to constrain to specific arguments.
-
#
-
# A message expectation will fail if the message is received with different
-
# arguments.
-
#
-
# @example
-
#
-
# cart.stub(:add) { :failure }
-
# cart.stub(:add).with(Book.new(:isbn => 1934356379)) { :success }
-
# cart.add(Book.new(:isbn => 1234567890))
-
# # => :failure
-
# cart.add(Book.new(:isbn => 1934356379))
-
# # => :success
-
#
-
# cart.should_receive(:add).with(Book.new(:isbn => 1934356379)) { :success }
-
# cart.add(Book.new(:isbn => 1234567890))
-
# # => failed expectation
-
# cart.add(Book.new(:isbn => 1934356379))
-
# # => passes
-
1
def with(*args, &block)
-
self.inner_implementation_action = block if block_given? unless args.empty?
-
@argument_list_matcher = ArgumentListMatcher.new(*args, &block)
-
self
-
end
-
-
# Constrain a message expectation to be received a specific number of
-
# times.
-
#
-
# @example
-
#
-
# dealer.should_receive(:deal_card).exactly(10).times
-
1
def exactly(n, &block)
-
self.inner_implementation_action = block
-
set_expected_received_count :exactly, n
-
self
-
end
-
-
# Constrain a message expectation to be received at least a specific
-
# number of times.
-
#
-
# @example
-
#
-
# dealer.should_receive(:deal_card).at_least(9).times
-
1
def at_least(n, &block)
-
self.inner_implementation_action = block
-
set_expected_received_count :at_least, n
-
self
-
end
-
-
# Constrain a message expectation to be received at most a specific
-
# number of times.
-
#
-
# @example
-
#
-
# dealer.should_receive(:deal_card).at_most(10).times
-
1
def at_most(n, &block)
-
self.inner_implementation_action = block
-
set_expected_received_count :at_most, n
-
self
-
end
-
-
# Syntactic sugar for `exactly`, `at_least` and `at_most`
-
#
-
# @example
-
#
-
# dealer.should_receive(:deal_card).exactly(10).times
-
# dealer.should_receive(:deal_card).at_least(10).times
-
# dealer.should_receive(:deal_card).at_most(10).times
-
1
def times(&block)
-
self.inner_implementation_action = block
-
self
-
end
-
-
-
# Allows an expected message to be received any number of times.
-
1
def any_number_of_times(&block)
-
self.inner_implementation_action = block
-
@expected_received_count = :any
-
self
-
end
-
-
# Expect a message not to be received at all.
-
#
-
# @example
-
#
-
# car.should_receive(:stop).never
-
1
def never
-
@expected_received_count = 0
-
self
-
end
-
-
# Expect a message to be received exactly one time.
-
#
-
# @example
-
#
-
# car.should_receive(:go).once
-
1
def once(&block)
-
self.inner_implementation_action = block
-
set_expected_received_count :exactly, 1
-
self
-
end
-
-
# Expect a message to be received exactly two times.
-
#
-
# @example
-
#
-
# car.should_receive(:go).twice
-
1
def twice(&block)
-
self.inner_implementation_action = block
-
set_expected_received_count :exactly, 2
-
self
-
end
-
-
# Expect messages to be received in a specific order.
-
#
-
# @example
-
#
-
# api.should_receive(:prepare).ordered
-
# api.should_receive(:run).ordered
-
# api.should_receive(:finish).ordered
-
1
def ordered(&block)
-
self.inner_implementation_action = block
-
@order_group.register(self)
-
@ordered = true
-
self
-
end
-
-
# @private
-
1
def negative_expectation_for?(message)
-
return false
-
end
-
-
# @private
-
1
def actual_received_count_matters?
-
@at_least || @at_most || @exactly
-
end
-
-
# @private
-
1
def increase_actual_received_count!
-
@actual_received_count += 1
-
end
-
-
1
private
-
-
1
def failed_fast?
-
@failed_fast
-
end
-
-
1
def set_expected_received_count(relativity, n)
-
@at_least = (relativity == :at_least)
-
@at_most = (relativity == :at_most)
-
@exactly = (relativity == :exactly)
-
@expected_received_count = case n
-
when Numeric then n
-
when :once then 1
-
when :twice then 2
-
end
-
end
-
-
1
def initial_implementation_action=(action)
-
implementation.initial_action = action
-
end
-
-
1
def inner_implementation_action=(action)
-
implementation.inner_action = action if action
-
end
-
-
1
def terminal_implementation_action=(action)
-
implementation.terminal_action = action
-
end
-
end
-
-
# @private
-
1
class NegativeMessageExpectation < MessageExpectation
-
# @private
-
1
def initialize(error_generator, expectation_ordering, expected_from, method_double, &implementation)
-
super(error_generator, expectation_ordering, expected_from, method_double, 0, {}, &implementation)
-
end
-
-
1
def and_return(*)
-
# no-op
-
# @deprecated and_return is not supported with negative message expectations.
-
RSpec::Mocks.warn_deprecation <<-MSG
-
-
DEPRECATION: `and_return` with `should_not_receive` is deprecated. Called from #{caller(0)[1]}
-
MSG
-
end
-
-
# @private
-
1
def negative_expectation_for?(message)
-
return @message == message
-
end
-
end
-
-
# Handles the implementation of an `and_yield` declaration.
-
# @private
-
1
class AndYieldImplementation
-
1
def initialize(args_to_yield, eval_context, error_generator)
-
@args_to_yield = args_to_yield
-
@eval_context = eval_context
-
@error_generator = error_generator
-
end
-
-
1
def arity
-
0
-
end
-
-
1
def call(&block)
-
return if @args_to_yield.empty? && @eval_context.nil?
-
-
@error_generator.raise_missing_block_error @args_to_yield unless block
-
value = nil
-
@args_to_yield.each do |args|
-
if block.arity > -1 && args.length != block.arity
-
@error_generator.raise_wrong_arity_error args, block.arity
-
end
-
value = @eval_context ? @eval_context.instance_exec(*args, &block) : block.call(*args)
-
end
-
value
-
end
-
end
-
-
# Handles the implementation of an `and_return` implementation.
-
# @private
-
1
class AndReturnImplementation
-
1
def initialize(values_to_return)
-
@values_to_return = values_to_return
-
end
-
-
1
def arity
-
0
-
end
-
-
1
def call(&block)
-
if @values_to_return.size > 1
-
@values_to_return.shift
-
else
-
@values_to_return.first
-
end
-
end
-
end
-
-
# Represents a configured implementation. Takes into account
-
# any number of sub-implementations.
-
# @private
-
1
class Implementation
-
1
attr_accessor :initial_action, :inner_action, :terminal_action
-
-
1
def call(*args, &block)
-
actions.map do |action|
-
action.arity.zero? ? action.call(&block) : action.call(*args, &block)
-
end.last
-
end
-
-
1
def present?
-
actions.any?
-
end
-
-
1
private
-
-
1
def actions
-
[initial_action, inner_action, terminal_action].compact
-
end
-
end
-
-
# Represents an `and_call_original` implementation.
-
# @private
-
1
class AndCallOriginalImplementation
-
1
def initialize(method)
-
@method = method
-
end
-
-
1
CannotModifyFurtherError = Class.new(StandardError)
-
-
1
def initial_action=(value)
-
raise cannot_modify_further_error
-
end
-
-
1
def inner_action=(value)
-
raise cannot_modify_further_error
-
end
-
-
1
def terminal_action=(value)
-
raise cannot_modify_further_error
-
end
-
-
1
def present?
-
true
-
end
-
-
1
def call(*args, &block)
-
@method.call(*args, &block)
-
end
-
-
1
private
-
-
1
def cannot_modify_further_error
-
CannotModifyFurtherError.new "This method has already been configured " +
-
"to call the original implementation, and cannot be modified further."
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
# @private
-
1
class MethodDouble < Hash
-
# @private
-
1
attr_reader :method_name, :object
-
-
# @private
-
1
def initialize(object, method_name, proxy)
-
@method_name = method_name
-
@object = object
-
@proxy = proxy
-
-
@method_stasher = InstanceMethodStasher.new(object_singleton_class, @method_name)
-
@method_is_proxied = false
-
store(:expectations, [])
-
store(:stubs, [])
-
end
-
-
# @private
-
1
def expectations
-
self[:expectations]
-
end
-
-
# @private
-
1
def stubs
-
self[:stubs]
-
end
-
-
# @private
-
1
def visibility
-
if TestDouble === @object
-
'public'
-
elsif object_singleton_class.private_method_defined?(@method_name)
-
'private'
-
elsif object_singleton_class.protected_method_defined?(@method_name)
-
'protected'
-
else
-
'public'
-
end
-
end
-
-
# @private
-
1
def original_method
-
if @method_stasher.method_is_stashed?
-
# Example: a singleton method defined on @object
-
::RSpec::Mocks.method_handle_for(@object, @method_stasher.stashed_method_name)
-
elsif meth = original_unrecorded_any_instance_method
-
# Example: a method that has been mocked through
-
# klass.any_instance.should_receive(:msg).and_call_original
-
# any_instance.should_receive(:msg) causes the method to be
-
# replaced with a proxy method, and then `and_call_original`
-
# is recorded and played back on the object instance. We need
-
# special handling here to get a handle on the original method
-
# object rather than the proxy method.
-
meth
-
else
-
begin
-
# Example: an instance method defined on one of @object's ancestors.
-
original_method_from_ancestor(object_singleton_class.ancestors)
-
rescue NameError
-
raise unless @object.respond_to?(:superclass)
-
-
# Example: a singleton method defined on @object's superclass.
-
#
-
# Note: we have to give precedence to instance methods
-
# defined on @object's class, because in a case like:
-
#
-
# `klass.should_receive(:new).and_call_original`
-
#
-
# ...we want `Class#new` bound to `klass` (which will return
-
# an instance of `klass`), not `klass.superclass.new` (which
-
# would return an instance of `klass.superclass`).
-
original_method_from_superclass
-
end
-
end
-
rescue NameError
-
# We have no way of knowing if the object's method_missing
-
# will handle this message or not...but we can at least try.
-
# If it's not handled, a `NoMethodError` will be raised, just
-
# like normally.
-
Proc.new do |*args, &block|
-
@object.__send__(:method_missing, @method_name, *args, &block)
-
end
-
end
-
-
1
def original_unrecorded_any_instance_method
-
return nil unless any_instance_class_recorder_observing_method?(@object.class)
-
alias_name = @object.class.__recorder.build_alias_method_name(@method_name)
-
@object.method(alias_name)
-
end
-
-
1
def any_instance_class_recorder_observing_method?(klass)
-
return true if klass.__recorder.already_observing?(@method_name)
-
superklass = klass.superclass
-
return false if superklass.nil?
-
any_instance_class_recorder_observing_method?(superklass)
-
end
-
-
1
def original_method_from_ancestor(ancestors)
-
klass, *rest = ancestors
-
klass.instance_method(@method_name).bind(@object)
-
rescue NameError
-
raise if rest.empty?
-
original_method_from_ancestor(rest)
-
end
-
-
1
if RUBY_VERSION.to_f > 1.8
-
# @private
-
1
def original_method_from_superclass
-
@object.superclass.
-
singleton_class.
-
instance_method(@method_name).
-
bind(@object)
-
end
-
else
-
# Our implementation for 1.9 (above) causes an error on 1.8:
-
# TypeError: singleton method bound for a different object
-
#
-
# This doesn't work quite right in all circumstances but it's the
-
# best we can do.
-
# @private
-
def original_method_from_superclass
-
::Kernel.warn <<-WARNING.gsub(/^ +\|/, '')
-
|
-
|WARNING: On ruby 1.8, rspec-mocks is unable to bind the original
-
|`#{@method_name}` method to your partial mock object (#{@object})
-
|for `and_call_original`. The superclass's `#{@method_name}` is being
-
|used instead; however, it may not work correctly when executed due
-
|to the fact that `self` will be #{@object.superclass}, not #{@object}.
-
|
-
|Called from: #{caller[2]}
-
WARNING
-
-
@object.superclass.method(@method_name)
-
end
-
end
-
# @private
-
1
def object_singleton_class
-
class << @object; self; end
-
end
-
-
# @private
-
1
def configure_method
-
RSpec::Mocks::space.add(@object) if RSpec::Mocks::space
-
warn_if_nil_class
-
@original_visibility = visibility_for_method
-
@method_stasher.stash unless @method_is_proxied
-
define_proxy_method
-
end
-
-
# @private
-
1
def define_proxy_method
-
return if @method_is_proxied
-
-
object_singleton_class.class_eval <<-EOF, __FILE__, __LINE__ + 1
-
def #{@method_name}(*args, &block)
-
__mock_proxy.message_received :#{@method_name}, *args, &block
-
end
-
#{visibility_for_method}
-
EOF
-
@method_is_proxied = true
-
end
-
-
# @private
-
1
def visibility_for_method
-
"#{visibility} :#{method_name}"
-
end
-
-
# @private
-
1
def restore_original_method
-
return unless @method_is_proxied
-
-
object_singleton_class.__send__(:remove_method, @method_name)
-
@method_stasher.restore
-
restore_original_visibility
-
-
@method_is_proxied = false
-
end
-
-
# @private
-
1
def restore_original_visibility
-
return unless object_singleton_class.method_defined?(@method_name) || object_singleton_class.private_method_defined?(@method_name)
-
object_singleton_class.class_eval(@original_visibility, __FILE__, __LINE__)
-
end
-
-
# @private
-
1
def verify
-
expectations.each {|e| e.verify_messages_received}
-
end
-
-
# @private
-
1
def reset
-
reset_nil_expectations_warning
-
restore_original_method
-
clear
-
end
-
-
# @private
-
1
def clear
-
expectations.clear
-
stubs.clear
-
end
-
-
# @private
-
1
def add_expectation(error_generator, expectation_ordering, expected_from, opts, &implementation)
-
configure_method
-
expectation = MessageExpectation.new(error_generator, expectation_ordering,
-
expected_from, self, 1, opts, &implementation)
-
expectations << expectation
-
expectation
-
end
-
-
# @private
-
1
def add_negative_expectation(error_generator, expectation_ordering, expected_from, &implementation)
-
configure_method
-
expectation = NegativeMessageExpectation.new(error_generator, expectation_ordering,
-
expected_from, self, &implementation)
-
expectations.unshift expectation
-
expectation
-
end
-
-
# @private
-
1
def add_stub(error_generator, expectation_ordering, expected_from, opts={}, &implementation)
-
configure_method
-
stub = MessageExpectation.new(error_generator, expectation_ordering, expected_from,
-
self, :any, opts, &implementation)
-
stubs.unshift stub
-
stub
-
end
-
-
# @private
-
1
def add_default_stub(*args, &implementation)
-
return if stubs.any?
-
add_stub(*args, &implementation)
-
end
-
-
# @private
-
1
def remove_stub
-
raise_method_not_stubbed_error if stubs.empty?
-
expectations.empty? ? reset : stubs.clear
-
end
-
-
# @private
-
1
def proxy_for_nil_class?
-
NilClass === @object
-
end
-
-
# @private
-
1
def warn_if_nil_class
-
if proxy_for_nil_class? & RSpec::Mocks::Proxy.warn_about_expectations_on_nil
-
Kernel.warn("An expectation of :#{@method_name} was set on nil. Called from #{caller[4]}. Use allow_message_expectations_on_nil to disable warnings.")
-
end
-
end
-
-
# @private
-
1
def raise_method_not_stubbed_error
-
raise MockExpectationError, "The method `#{method_name}` was not stubbed or was already unstubbed"
-
end
-
-
# @private
-
1
def reset_nil_expectations_warning
-
RSpec::Mocks::Proxy.warn_about_expectations_on_nil = true if proxy_for_nil_class?
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
# Methods that are added to every object.
-
1
module Methods
-
# Sets and expectation that this object should receive a message before
-
# the end of the example.
-
#
-
# @example
-
#
-
# logger = double('logger')
-
# thing_that_logs = ThingThatLogs.new(logger)
-
# logger.should_receive(:log)
-
# thing_that_logs.do_something_that_logs_a_message
-
1
def should_receive(message, opts={}, &block)
-
__mock_proxy.add_message_expectation(opts[:expected_from] || caller(1)[0], message.to_sym, opts, &block)
-
end
-
-
# Sets and expectation that this object should _not_ receive a message
-
# during this example.
-
1
def should_not_receive(message, &block)
-
__mock_proxy.add_negative_message_expectation(caller(1)[0], message.to_sym, &block)
-
end
-
-
# Tells the object to respond to the message with the specified value.
-
#
-
# @example
-
#
-
# counter.stub(:count).and_return(37)
-
# counter.stub(:count => 37)
-
# counter.stub(:count) { 37 }
-
1
def stub(message_or_hash, opts={}, &block)
-
if Hash === message_or_hash
-
message_or_hash.each {|message, value| stub(message).and_return value }
-
else
-
__mock_proxy.add_stub(caller(1)[0], message_or_hash.to_sym, opts, &block)
-
end
-
end
-
-
# Removes a stub. On a double, the object will no longer respond to
-
# `message`. On a real object, the original method (if it exists) is
-
# restored.
-
#
-
# This is rarely used, but can be useful when a stub is set up during a
-
# shared `before` hook for the common case, but you want to replace it
-
# for a special case.
-
1
def unstub(message)
-
__mock_proxy.remove_stub(message)
-
end
-
-
1
alias_method :stub!, :stub
-
1
alias_method :unstub!, :unstub
-
-
# @overload stub_chain(method1, method2)
-
# @overload stub_chain("method1.method2")
-
# @overload stub_chain(method1, method_to_value_hash)
-
#
-
# Stubs a chain of methods.
-
#
-
# ## Warning:
-
#
-
# Chains can be arbitrarily long, which makes it quite painless to
-
# violate the Law of Demeter in violent ways, so you should consider any
-
# use of `stub_chain` a code smell. Even though not all code smells
-
# indicate real problems (think fluent interfaces), `stub_chain` still
-
# results in brittle examples. For example, if you write
-
# `foo.stub_chain(:bar, :baz => 37)` in a spec and then the
-
# implementation calls `foo.baz.bar`, the stub will not work.
-
#
-
# @example
-
#
-
# double.stub_chain("foo.bar") { :baz }
-
# double.stub_chain(:foo, :bar => :baz)
-
# double.stub_chain(:foo, :bar) { :baz }
-
#
-
# # Given any of ^^ these three forms ^^:
-
# double.foo.bar # => :baz
-
#
-
# # Common use in Rails/ActiveRecord:
-
# Article.stub_chain("recent.published") { [Article.new] }
-
1
def stub_chain(*chain, &blk)
-
chain, blk = format_chain(*chain, &blk)
-
if chain.length > 1
-
if matching_stub = __mock_proxy.__send__(:find_matching_method_stub, chain[0].to_sym)
-
chain.shift
-
matching_stub.invoke(nil).stub_chain(*chain, &blk)
-
else
-
next_in_chain = Mock.new
-
stub(chain.shift) { next_in_chain }
-
next_in_chain.stub_chain(*chain, &blk)
-
end
-
else
-
stub(chain.shift, &blk)
-
end
-
end
-
-
# Tells the object to respond to all messages. If specific stub values
-
# are declared, they'll work as expected. If not, the receiver is
-
# returned.
-
1
def as_null_object
-
@_null_object = true
-
__mock_proxy.as_null_object
-
end
-
-
# Returns true if this object has received `as_null_object`
-
1
def null_object?
-
defined?(@_null_object)
-
end
-
-
# @private
-
1
def received_message?(message, *args, &block)
-
__mock_proxy.received_message?(message, *args, &block)
-
end
-
-
# @private
-
1
def rspec_verify
-
__mock_proxy.verify
-
end
-
-
# @private
-
1
def rspec_reset
-
__mock_proxy.reset
-
end
-
-
1
private
-
-
1
def __mock_proxy
-
@mock_proxy ||= begin
-
mp = if TestDouble === self
-
Proxy.new(self, @name, @options)
-
else
-
Proxy.new(self)
-
end
-
-
Serialization.fix_for(self)
-
mp
-
end
-
end
-
-
1
def __remove_mock_proxy
-
@mock_proxy = nil
-
end
-
-
1
def format_chain(*chain, &blk)
-
if Hash === chain.last
-
hash = chain.pop
-
hash.each do |k,v|
-
chain << k
-
blk = lambda { v }
-
end
-
end
-
return chain.join('.').split('.'), blk
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
1
class Mock
-
1
include TestDouble
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
# Provides recursive constant lookup methods useful for
-
# constant stubbing.
-
# @api private
-
1
module RecursiveConstMethods
-
# We only want to consider constants that are defined directly on a
-
# particular module, and not include top-level/inherited constants.
-
# Unfortunately, the constant API changed between 1.8 and 1.9, so
-
# we need to conditionally define methods to ignore the top-level/inherited
-
# constants.
-
#
-
# Given:
-
# class A; B = 1; end
-
# class C < A; end
-
#
-
# On 1.8:
-
# - C.const_get("Hash") # => ::Hash
-
# - C.const_defined?("Hash") # => false
-
# - C.constants # => ["B"]
-
# - None of these methods accept the extra `inherit` argument
-
# On 1.9:
-
# - C.const_get("Hash") # => ::Hash
-
# - C.const_defined?("Hash") # => true
-
# - C.const_get("Hash", false) # => raises NameError
-
# - C.const_defined?("Hash", false) # => false
-
# - C.constants # => [:B]
-
# - C.constants(false) #=> []
-
1
if Module.method(:const_defined?).arity == 1
-
def const_defined_on?(mod, const_name)
-
mod.const_defined?(const_name)
-
end
-
-
def get_const_defined_on(mod, const_name)
-
if const_defined_on?(mod, const_name)
-
return mod.const_get(const_name)
-
end
-
-
raise NameError, "uninitialized constant #{mod.name}::#{const_name}"
-
end
-
-
def constants_defined_on(mod)
-
mod.constants.select { |c| const_defined_on?(mod, c) }
-
end
-
else
-
1
def const_defined_on?(mod, const_name)
-
mod.const_defined?(const_name, false)
-
end
-
-
1
def get_const_defined_on(mod, const_name)
-
mod.const_get(const_name, false)
-
end
-
-
1
def constants_defined_on(mod)
-
mod.constants(false)
-
end
-
end
-
-
1
def recursive_const_get(const_name)
-
normalize_const_name(const_name).split('::').inject(Object) do |mod, name|
-
get_const_defined_on(mod, name)
-
end
-
end
-
-
1
def recursive_const_defined?(const_name)
-
normalize_const_name(const_name).split('::').inject([Object, '']) do |(mod, full_name), name|
-
yield(full_name, name) if block_given? && !mod.is_a?(Module)
-
return false unless const_defined_on?(mod, name)
-
[get_const_defined_on(mod, name), [mod, name].join('::')]
-
end
-
end
-
-
1
def normalize_const_name(const_name)
-
const_name.sub(/\A::/, '')
-
end
-
end
-
-
# Provides information about constants that may (or may not)
-
# have been mutated by rspec-mocks.
-
1
class Constant
-
1
extend RecursiveConstMethods
-
-
# @api private
-
1
def initialize(name)
-
@name = name
-
end
-
-
# @return [String] The fully qualified name of the constant.
-
1
attr_reader :name
-
-
# @return [Object, nil] The original value (e.g. before it
-
# was mutated by rspec-mocks) of the constant, or
-
# nil if the constant was not previously defined.
-
1
attr_accessor :original_value
-
-
# @api private
-
1
attr_writer :previously_defined, :stubbed, :hidden
-
-
# @return [Boolean] Whether or not the constant was defined
-
# before the current example.
-
1
def previously_defined?
-
@previously_defined
-
end
-
-
# @return [Boolean] Whether or not rspec-mocks has mutated
-
# (stubbed or hidden) this constant.
-
1
def mutated?
-
@stubbed || @hidden
-
end
-
-
# @return [Boolean] Whether or not rspec-mocks has stubbed
-
# this constant.
-
1
def stubbed?
-
@stubbed
-
end
-
-
# @return [Boolean] Whether or not rspec-mocks has hidden
-
# this constant.
-
1
def hidden?
-
@hidden
-
end
-
-
1
def to_s
-
"#<#{self.class.name} #{name}>"
-
end
-
1
alias inspect to_s
-
-
# @api private
-
1
def self.unmutated(name)
-
const = new(name)
-
const.previously_defined = recursive_const_defined?(name)
-
const.stubbed = false
-
const.hidden = false
-
const.original_value = recursive_const_get(name) if const.previously_defined?
-
-
const
-
end
-
1
private_class_method :unmutated
-
-
# Queries rspec-mocks to find out information about the named constant.
-
#
-
# @param [String] name the name of the constant
-
# @return [Constant] an object contaning information about the named
-
# constant.
-
1
def self.original(name)
-
mutator = ConstantMutator.find(name)
-
mutator ? mutator.to_constant : unmutated(name)
-
end
-
end
-
-
# Provides a means to stub constants.
-
1
class ConstantMutator
-
1
extend RecursiveConstMethods
-
-
# Stubs a constant.
-
#
-
# @param (see ExampleMethods#stub_const)
-
# @option (see ExampleMethods#stub_const)
-
# @return (see ExampleMethods#stub_const)
-
#
-
# @see ExampleMethods#stub_const
-
# @note It's recommended that you use `stub_const` in your
-
# examples. This is an alternate public API that is provided
-
# so you can stub constants in other contexts (e.g. helper
-
# classes).
-
1
def self.stub(constant_name, value, options = {})
-
mutator = if recursive_const_defined?(constant_name, &raise_on_invalid_const)
-
DefinedConstantReplacer
-
else
-
UndefinedConstantSetter
-
end
-
-
mutate(mutator.new(constant_name, value, options[:transfer_nested_constants]))
-
value
-
end
-
-
# Hides a constant.
-
#
-
# @param (see ExampleMethods#hide_const)
-
#
-
# @see ExampleMethods#hide_const
-
# @note It's recommended that you use `hide_const` in your
-
# examples. This is an alternate public API that is provided
-
# so you can hide constants in other contexts (e.g. helper
-
# classes).
-
1
def self.hide(constant_name)
-
return unless recursive_const_defined?(constant_name)
-
-
mutate(ConstantHider.new(constant_name, nil, { }))
-
nil
-
end
-
-
# Contains common functionality used by all of the constant mutators.
-
#
-
# @api private
-
1
class BaseMutator
-
1
include RecursiveConstMethods
-
-
1
attr_reader :original_value, :full_constant_name
-
-
1
def initialize(full_constant_name, mutated_value, transfer_nested_constants)
-
@full_constant_name = normalize_const_name(full_constant_name)
-
@mutated_value = mutated_value
-
@transfer_nested_constants = transfer_nested_constants
-
@context_parts = @full_constant_name.split('::')
-
@const_name = @context_parts.pop
-
end
-
-
1
def to_constant
-
const = Constant.new(full_constant_name)
-
const.original_value = original_value
-
-
const
-
end
-
end
-
-
# Hides a defined constant for the duration of an example.
-
#
-
# @api private
-
1
class ConstantHider < BaseMutator
-
1
def mutate
-
@context = recursive_const_get(@context_parts.join('::'))
-
@original_value = get_const_defined_on(@context, @const_name)
-
-
@context.send(:remove_const, @const_name)
-
end
-
-
1
def to_constant
-
const = super
-
const.hidden = true
-
const.previously_defined = true
-
-
const
-
end
-
-
1
def rspec_reset
-
@context.const_set(@const_name, @original_value)
-
end
-
end
-
-
# Replaces a defined constant for the duration of an example.
-
#
-
# @api private
-
1
class DefinedConstantReplacer < BaseMutator
-
1
def mutate
-
@context = recursive_const_get(@context_parts.join('::'))
-
@original_value = get_const_defined_on(@context, @const_name)
-
-
constants_to_transfer = verify_constants_to_transfer!
-
-
@context.send(:remove_const, @const_name)
-
@context.const_set(@const_name, @mutated_value)
-
-
transfer_nested_constants(constants_to_transfer)
-
end
-
-
1
def to_constant
-
const = super
-
const.stubbed = true
-
const.previously_defined = true
-
-
const
-
end
-
-
1
def rspec_reset
-
@context.send(:remove_const, @const_name)
-
@context.const_set(@const_name, @original_value)
-
end
-
-
1
def transfer_nested_constants(constants)
-
constants.each do |const|
-
@mutated_value.const_set(const, get_const_defined_on(original_value, const))
-
end
-
end
-
-
1
def verify_constants_to_transfer!
-
return [] unless @transfer_nested_constants
-
-
{ @original_value => "the original value", @mutated_value => "the stubbed value" }.each do |value, description|
-
unless value.respond_to?(:constants)
-
raise ArgumentError,
-
"Cannot transfer nested constants for #{@full_constant_name} " +
-
"since #{description} is not a class or module and only classes " +
-
"and modules support nested constants."
-
end
-
end
-
-
if @transfer_nested_constants.is_a?(Array)
-
@transfer_nested_constants = @transfer_nested_constants.map(&:to_s) if RUBY_VERSION == '1.8.7'
-
undefined_constants = @transfer_nested_constants - constants_defined_on(@original_value)
-
-
if undefined_constants.any?
-
available_constants = constants_defined_on(@original_value) - @transfer_nested_constants
-
raise ArgumentError,
-
"Cannot transfer nested constant(s) #{undefined_constants.join(' and ')} " +
-
"for #{@full_constant_name} since they are not defined. Did you mean " +
-
"#{available_constants.join(' or ')}?"
-
end
-
-
@transfer_nested_constants
-
else
-
constants_defined_on(@original_value)
-
end
-
end
-
end
-
-
# Sets an undefined constant for the duration of an example.
-
#
-
# @api private
-
1
class UndefinedConstantSetter < BaseMutator
-
1
def mutate
-
remaining_parts = @context_parts.dup
-
@deepest_defined_const = @context_parts.inject(Object) do |klass, name|
-
break klass unless const_defined_on?(klass, name)
-
remaining_parts.shift
-
get_const_defined_on(klass, name)
-
end
-
-
context = remaining_parts.inject(@deepest_defined_const) do |klass, name|
-
klass.const_set(name, Module.new)
-
end
-
-
@const_to_remove = remaining_parts.first || @const_name
-
context.const_set(@const_name, @mutated_value)
-
end
-
-
1
def to_constant
-
const = super
-
const.stubbed = true
-
const.previously_defined = false
-
-
const
-
end
-
-
1
def rspec_reset
-
@deepest_defined_const.send(:remove_const, @const_to_remove)
-
end
-
end
-
-
# Uses the mutator to mutate (stub or hide) a constant. Ensures that
-
# the mutator is correctly registered so it can be backed out at the end
-
# of the test.
-
#
-
# @api private
-
1
def self.mutate(mutator)
-
register_mutator(mutator)
-
mutator.mutate
-
ensure_registered_with_mocks_space
-
end
-
-
# Ensures the constant stubbing is registered with
-
# rspec-mocks space so that stubbed constants can
-
# be restored when examples finish.
-
#
-
# @api private
-
1
def self.ensure_registered_with_mocks_space
-
return if defined?(@registered_with_mocks_space) && @registered_with_mocks_space
-
::RSpec::Mocks.space.add(self)
-
@registered_with_mocks_space = true
-
end
-
-
# Resets all stubbed constants. This is called automatically
-
# by rspec-mocks when an example finishes.
-
#
-
# @api private
-
1
def self.rspec_reset
-
@registered_with_mocks_space = false
-
-
# We use reverse order so that if the same constant
-
# was stubbed multiple times, the original value gets
-
# properly restored.
-
mutators.reverse.each { |s| s.rspec_reset }
-
-
mutators.clear
-
end
-
-
# The list of constant mutators that have been used for
-
# the current example.
-
#
-
# @api private
-
1
def self.mutators
-
@mutators ||= []
-
end
-
-
# @api private
-
1
def self.register_mutator(mutator)
-
mutators << mutator
-
end
-
-
1
def self.find(name)
-
mutators.find { |s| s.full_constant_name == name }
-
end
-
-
# Used internally by the constant stubbing to raise a helpful
-
# error when a constant like "A::B::C" is stubbed and A::B is
-
# not a module (and thus, it's impossible to define "A::B::C"
-
# since only modules can have nested constants).
-
#
-
# @api private
-
1
def self.raise_on_invalid_const
-
lambda do |const_name, failed_name|
-
raise "Cannot stub constant #{failed_name} on #{const_name} " +
-
"since #{const_name} is not a module."
-
end
-
end
-
end
-
-
# Keeps backwards compatibility since we had released an rspec-mocks that
-
# only supported stubbing. Later, we released the hide_const feature and
-
# decided that the term "mutator" was a better term to wrap up the concept
-
# of both stubbing and hiding.
-
1
ConstantStubber = ConstantMutator
-
end
-
end
-
-
1
module RSpec
-
1
module Mocks
-
# @private
-
1
class OrderGroup
-
1
def initialize
-
1
@ordering = Array.new
-
end
-
-
# @private
-
1
def register(expectation)
-
@ordering << expectation
-
end
-
-
# @private
-
1
def ready_for?(expectation)
-
@ordering.first == expectation
-
end
-
-
# @private
-
1
def consume
-
@ordering.shift
-
end
-
-
# @private
-
1
def handle_order_constraint(expectation)
-
return unless @ordering.include?(expectation)
-
return consume if ready_for?(expectation)
-
expectation.raise_out_of_order_error
-
end
-
-
1
def clear
-
27
@ordering.clear
-
end
-
-
1
def empty?
-
@ordering.empty?
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
# @private
-
1
class Proxy
-
1
class << self
-
# @private
-
1
def warn_about_expectations_on_nil
-
defined?(@warn_about_expectations_on_nil) ? @warn_about_expectations_on_nil : true
-
end
-
-
# @private
-
1
def warn_about_expectations_on_nil=(new_value)
-
@warn_about_expectations_on_nil = new_value
-
end
-
-
# @private
-
1
def allow_message_expectations_on_nil
-
@warn_about_expectations_on_nil = false
-
-
# ensure nil.rspec_verify is called even if an expectation is not set in the example
-
# otherwise the allowance would effect subsequent examples
-
RSpec::Mocks::space.add(nil) unless RSpec::Mocks::space.nil?
-
end
-
-
# @private
-
1
def allow_message_expectations_on_nil?
-
!warn_about_expectations_on_nil
-
end
-
end
-
-
# @private
-
1
def initialize(object, name=nil, options={})
-
@object = object
-
@name = name
-
@error_generator = ErrorGenerator.new object, name, options
-
@expectation_ordering = RSpec::Mocks::space.expectation_ordering
-
@messages_received = []
-
@options = options
-
@already_proxied_respond_to = false
-
@null_object = false
-
end
-
-
# @private
-
1
def null_object?
-
@null_object
-
end
-
-
# @private
-
# Tells the object to ignore any messages that aren't explicitly set as
-
# stubs or message expectations.
-
1
def as_null_object
-
@null_object = true
-
@object
-
end
-
-
# @private
-
1
def already_proxied_respond_to
-
@already_proxied_respond_to = true
-
end
-
-
# @private
-
1
def already_proxied_respond_to?
-
@already_proxied_respond_to
-
end
-
-
# @private
-
1
def add_message_expectation(location, method_name, opts={}, &block)
-
meth_double = method_double[method_name]
-
-
if null_object? && !block
-
meth_double.add_default_stub(@error_generator, @expectation_ordering, location, opts) do
-
@object
-
end
-
end
-
-
meth_double.add_expectation @error_generator, @expectation_ordering, location, opts, &block
-
end
-
-
# @private
-
1
def add_negative_message_expectation(location, method_name, &implementation)
-
method_double[method_name].add_negative_expectation @error_generator, @expectation_ordering, location, &implementation
-
end
-
-
# @private
-
1
def add_stub(location, method_name, opts={}, &implementation)
-
method_double[method_name].add_stub @error_generator, @expectation_ordering, location, opts, &implementation
-
end
-
-
# @private
-
1
def remove_stub(method_name)
-
method_double[method_name].remove_stub
-
end
-
-
# @private
-
1
def verify
-
method_doubles.each {|d| d.verify}
-
ensure
-
reset
-
end
-
-
# @private
-
1
def reset
-
method_doubles.each {|d| d.reset}
-
end
-
-
# @private
-
1
def received_message?(method_name, *args, &block)
-
@messages_received.any? {|array| array == [method_name, args, block]}
-
end
-
-
# @private
-
1
def has_negative_expectation?(message)
-
method_double[message].expectations.detect {|expectation| expectation.negative_expectation_for?(message)}
-
end
-
-
# @private
-
1
def record_message_received(message, *args, &block)
-
@messages_received << [message, args, block]
-
end
-
-
# @private
-
1
def message_received(message, *args, &block)
-
expectation = find_matching_expectation(message, *args)
-
stub = find_matching_method_stub(message, *args)
-
-
if (stub && expectation && expectation.called_max_times?) || (stub && !expectation)
-
expectation.increase_actual_received_count! if expectation && expectation.actual_received_count_matters?
-
if expectation = find_almost_matching_expectation(message, *args)
-
expectation.advise(*args) unless expectation.expected_messages_received?
-
end
-
stub.invoke(nil, *args, &block)
-
elsif expectation
-
expectation.invoke(stub, *args, &block)
-
elsif expectation = find_almost_matching_expectation(message, *args)
-
expectation.advise(*args) if null_object? unless expectation.expected_messages_received?
-
raise_unexpected_message_args_error(expectation, *args) unless (has_negative_expectation?(message) or null_object?)
-
elsif stub = find_almost_matching_stub(message, *args)
-
stub.advise(*args)
-
raise_missing_default_stub_error(stub, *args)
-
elsif @object.is_a?(Class)
-
@object.superclass.__send__(message, *args, &block)
-
else
-
@object.__send__(:method_missing, message, *args, &block)
-
end
-
end
-
-
# @private
-
1
def raise_unexpected_message_error(method_name, *args)
-
@error_generator.raise_unexpected_message_error method_name, *args
-
end
-
-
# @private
-
1
def raise_unexpected_message_args_error(expectation, *args)
-
@error_generator.raise_unexpected_message_args_error(expectation, *args)
-
end
-
-
# @private
-
1
def raise_missing_default_stub_error(expectation, *args)
-
@error_generator.raise_missing_default_stub_error(expectation, *args)
-
end
-
-
1
private
-
-
1
def method_double
-
@method_double ||= Hash.new {|h,k| h[k] = MethodDouble.new(@object, k, self) }
-
end
-
-
1
def method_doubles
-
method_double.values
-
end
-
-
1
def find_matching_expectation(method_name, *args)
-
find_best_matching_expectation_for(method_name) do |expectation|
-
expectation.matches?(method_name, *args)
-
end
-
end
-
-
1
def find_almost_matching_expectation(method_name, *args)
-
find_best_matching_expectation_for(method_name) do |expectation|
-
expectation.matches_name_but_not_args(method_name, *args)
-
end
-
end
-
-
1
def find_best_matching_expectation_for(method_name)
-
first_match = nil
-
-
method_double[method_name].expectations.each do |expectation|
-
next unless yield expectation
-
return expectation unless expectation.called_max_times?
-
first_match ||= expectation
-
end
-
-
first_match
-
end
-
-
1
def find_matching_method_stub(method_name, *args)
-
method_double[method_name].stubs.find {|stub| stub.matches?(method_name, *args)}
-
end
-
-
1
def find_almost_matching_stub(method_name, *args)
-
method_double[method_name].stubs.find {|stub| stub.matches_name_but_not_args(method_name, *args)}
-
end
-
end
-
end
-
end
-
1
require 'rspec/mocks/extensions/marshal'
-
1
require 'rspec/mocks/extensions/psych' if defined?(::Psych)
-
-
1
module RSpec
-
1
module Mocks
-
# @private
-
1
module Serialization
-
# @private
-
1
def self.fix_for(object)
-
object.extend(YAML) if defined?(::YAML)
-
rescue TypeError
-
# Can't extend Fixnums, Symbols, true, false, or nil
-
end
-
-
# @private
-
1
module YAML
-
# @private
-
1
def to_yaml(options = {})
-
return nil if defined?(::Psych) && options.respond_to?(:[]) && options[:nodump]
-
return super(options) unless instance_variable_defined?(:@mock_proxy)
-
-
mp = @mock_proxy
-
remove_instance_variable(:@mock_proxy)
-
-
begin
-
super(options)
-
ensure
-
@mock_proxy = mp
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
# @api private
-
1
class Space
-
1
def add(obj)
-
receivers << obj unless receivers.detect {|m| m.equal? obj}
-
end
-
-
1
def verify_all
-
27
receivers.each do |mock|
-
mock.rspec_verify
-
end
-
end
-
-
1
def reset_all
-
27
receivers.each do |mock|
-
mock.rspec_reset
-
end
-
27
receivers.clear
-
27
expectation_ordering.clear
-
end
-
-
1
def expectation_ordering
-
27
@expectation_ordering ||= OrderGroup.new
-
end
-
-
1
private
-
-
1
def receivers
-
81
@receivers ||= []
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
# Implements the methods needed for a pure test double. RSpec::Mocks::Mock
-
# includes this module, and it is provided for cases where you want a
-
# pure test double without subclassing RSpec::Mocks::Mock.
-
1
module TestDouble
-
1
include Methods
-
-
# Extends the TestDouble module onto the given object and
-
# initializes it as a test double.
-
#
-
# @example
-
#
-
# module = Module.new
-
# RSpec::Mocks::TestDouble.extend_onto(module, "MyMixin", :foo => "bar")
-
# module.foo #=> "bar"
-
1
def self.extend_onto(object, name=nil, stubs_and_options={})
-
object.extend self
-
object.send(:__initialize_as_test_double, name, stubs_and_options)
-
end
-
-
# Creates a new test double with a `name` (that will be used in error
-
# messages only)
-
1
def initialize(name=nil, stubs_and_options={})
-
__initialize_as_test_double(name, stubs_and_options)
-
end
-
-
# This allows for comparing the mock to other objects that proxy such as
-
# ActiveRecords belongs_to proxy objects. By making the other object run
-
# the comparison, we're sure the call gets delegated to the proxy
-
# target.
-
1
def ==(other)
-
other == __mock_proxy
-
end
-
-
# @private
-
1
def inspect
-
"#<#{self.class}:#{sprintf '0x%x', self.object_id} @name=#{@name.inspect}>"
-
end
-
-
# @private
-
1
def to_s
-
inspect.gsub('<','[').gsub('>',']')
-
end
-
-
1
alias_method :to_str, :to_s
-
-
# @private
-
1
def respond_to?(message, incl_private=false)
-
__mock_proxy.null_object? && message != :to_ary ? true : super
-
end
-
-
1
private
-
-
1
def __initialize_as_test_double(name=nil, stubs_and_options={})
-
if name.is_a?(Hash) && stubs_and_options.empty?
-
stubs_and_options = name
-
@name = nil
-
else
-
@name = name
-
end
-
@options = extract_options(stubs_and_options)
-
assign_stubs(stubs_and_options)
-
end
-
-
1
def method_missing(message, *args, &block)
-
raise NoMethodError if message == :to_ary
-
return 0 if message == :to_int && __mock_proxy.null_object?
-
__mock_proxy.record_message_received(message, *args, &block)
-
-
begin
-
__mock_proxy.null_object? ? self : super
-
rescue NameError
-
__mock_proxy.raise_unexpected_message_error(message, *args)
-
end
-
end
-
-
1
def extract_options(stubs_and_options)
-
if stubs_and_options[:null_object]
-
@null_object = stubs_and_options.delete(:null_object)
-
RSpec.deprecate(%Q["double('name', :null_object => true)"], %Q["double('name').as_null_object"])
-
end
-
options = {}
-
extract_option(stubs_and_options, options, :__declared_as, 'Mock')
-
options
-
end
-
-
1
def extract_option(source, target, key, default=nil)
-
if source[key]
-
target[key] = source.delete(key)
-
elsif default
-
target[key] = default
-
end
-
end
-
-
1
def assign_stubs(stubs)
-
stubs.each_pair do |message, response|
-
stub(message).and_return(response)
-
end
-
end
-
end
-
end
-
end
-
1
module RSpec
-
1
module Mocks
-
1
module Version
-
1
STRING = '2.13.1'
-
end
-
end
-
end
-
1
require 'treetop/ruby_extensions/string'
-
1
class String
-
1
def column_of(index)
-
return 1 if index == 0
-
newline_index = rindex("\n", index - 1)
-
if newline_index
-
index - newline_index
-
else
-
index + 1
-
end
-
end
-
-
1
def line_of(index)
-
self[0...index].count("\n") + 1
-
end
-
-
1
unless method_defined?(:blank?)
-
def blank?
-
self == ""
-
end
-
end
-
-
# The following methods are lifted from Facets 2.0.2
-
1
def tabto(n)
-
if self =~ /^( *)\S/
-
# Inlined due to collision with ActiveSupport 4.0: indent(n - $1.length)
-
m = n - $1.length
-
if m >= 0
-
gsub(/^/, ' ' * m)
-
else
-
gsub(/^ {0,#{-m}}/, "")
-
end
-
else
-
self
-
end
-
end
-
-
1
def treetop_camelize
-
to_s.gsub(/\/(.?)/){ "::" + $1.upcase }.gsub(/(^|_)(.)/){ $2.upcase }
-
end
-
end
-
1
require 'treetop/ruby_extensions'
-
-
1
require 'treetop/runtime/compiled_parser'
-
1
require 'treetop/runtime/syntax_node'
-
1
require 'treetop/runtime/terminal_parse_failure'
-
1
require 'treetop/runtime/interval_skip_list'
-
1
module Treetop
-
1
module Runtime
-
1
class CompiledParser
-
1
include Treetop::Runtime
-
-
1
attr_reader :input, :index, :max_terminal_failure_index
-
1
attr_writer :root
-
1
attr_accessor :consume_all_input
-
1
alias :consume_all_input? :consume_all_input
-
-
1
def initialize
-
18
self.consume_all_input = true
-
end
-
-
1
def parse(input, options = {})
-
18
prepare_to_parse(input)
-
18
@index = options[:index] if options[:index]
-
18
result = send("_nt_#{options[:root] || root}")
-
18
should_consume_all = options.include?(:consume_all_input) ? options[:consume_all_input] : consume_all_input?
-
18
return nil if (should_consume_all && index != input.size)
-
18
return SyntaxNode.new(input, index...(index + 1)) if result == true
-
18
return result
-
end
-
-
1
def failure_index
-
max_terminal_failure_index
-
end
-
-
1
def failure_line
-
@terminal_failures && input.line_of(failure_index)
-
end
-
-
1
def failure_column
-
@terminal_failures && input.column_of(failure_index)
-
end
-
-
1
def failure_reason
-
return nil unless (tf = terminal_failures) && tf.size > 0
-
"Expected " +
-
(tf.size == 1 ?
-
tf[0].expected_string :
-
"one of #{tf.map{|f| f.expected_string}.uniq*', '}"
-
) +
-
" at line #{failure_line}, column #{failure_column} (byte #{failure_index+1})" +
-
" after #{input[index...failure_index]}"
-
end
-
-
1
def terminal_failures
-
if @terminal_failures.empty? || @terminal_failures[0].is_a?(TerminalParseFailure)
-
@terminal_failures
-
else
-
@terminal_failures.map! {|tf_ary| TerminalParseFailure.new(*tf_ary) }
-
end
-
end
-
-
-
1
protected
-
-
1
attr_reader :node_cache, :input_length
-
1
attr_writer :index
-
-
1
def prepare_to_parse(input)
-
18
@input = input
-
18
@input_length = input.length
-
18
reset_index
-
402
@node_cache = Hash.new {|hash, key| hash[key] = Hash.new}
-
18
@regexps = {}
-
18
@terminal_failures = []
-
18
@max_terminal_failure_index = 0
-
end
-
-
1
def reset_index
-
18
@index = 0
-
end
-
-
1
def parse_anything(node_class = SyntaxNode, inline_module = nil)
-
if index < input.length
-
result = instantiate_node(node_class,input, index...(index + 1))
-
result.extend(inline_module) if inline_module
-
@index += 1
-
result
-
else
-
terminal_parse_failure("any character")
-
end
-
end
-
-
1
def instantiate_node(node_type,*args)
-
766
if node_type.respond_to? :new
-
766
node_type.new(*args)
-
else
-
SyntaxNode.new(*args).extend(node_type)
-
end
-
end
-
-
1
def has_terminal?(terminal, regex, index)
-
1450
if regex
-
632
rx = @regexps[terminal] ||= Regexp.new(terminal)
-
632
input.index(rx, index) == index
-
else
-
818
input[index, terminal.size] == terminal
-
end
-
end
-
-
1
def terminal_parse_failure(expected_string)
-
772
return nil if index < max_terminal_failure_index
-
706
if index > max_terminal_failure_index
-
66
@max_terminal_failure_index = index
-
66
@terminal_failures = []
-
end
-
706
@terminal_failures << [index, expected_string]
-
return nil
-
end
-
end
-
end
-
end
-
1
require 'treetop/runtime/interval_skip_list/interval_skip_list'
-
1
require 'treetop/runtime/interval_skip_list/head_node'
-
1
require 'treetop/runtime/interval_skip_list/node'
-
1
class IntervalSkipList
-
1
class HeadNode
-
1
attr_reader :height, :forward, :forward_markers
-
-
1
def initialize(height)
-
@height = height
-
@forward = Array.new(height, nil)
-
@forward_markers = Array.new(height) {|i| []}
-
end
-
-
1
def top_level
-
height - 1
-
end
-
end
-
end
-
1
class IntervalSkipList
-
1
attr_reader :probability
-
-
1
def initialize
-
@head = HeadNode.new(max_height)
-
@ranges = {}
-
@probability = 0.5
-
end
-
-
1
def max_height
-
3
-
end
-
-
1
def empty?
-
head.forward[0].nil?
-
end
-
-
1
def expire(range, length_change)
-
expired_markers, first_node_after_range = overlapping(range)
-
expired_markers.each { |marker| delete(marker) }
-
first_node_after_range.propagate_length_change(length_change)
-
end
-
-
1
def overlapping(range)
-
markers, first_node = containing_with_node(range.first)
-
-
cur_node = first_node
-
begin
-
markers.concat(cur_node.forward_markers.flatten)
-
cur_node = cur_node.forward[0]
-
end while cur_node.key < range.last
-
-
return markers.uniq, cur_node
-
end
-
-
1
def containing(n)
-
containing_with_node(n).first
-
end
-
-
1
def insert(range, marker)
-
ranges[marker] = range
-
first_node = insert_node(range.first)
-
first_node.endpoint_of.push(marker)
-
last_node = insert_node(range.last)
-
last_node.endpoint_of.push(marker)
-
-
cur_node = first_node
-
cur_level = first_node.top_level
-
while next_node_at_level_inside_range?(cur_node, cur_level, range)
-
while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range)
-
cur_level += 1
-
end
-
cur_node = mark_forward_path_at_level(cur_node, cur_level, marker)
-
end
-
-
while node_inside_range?(cur_node, range)
-
while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range)
-
cur_level -= 1
-
end
-
cur_node = mark_forward_path_at_level(cur_node, cur_level, marker)
-
end
-
end
-
-
1
def delete(marker)
-
range = ranges[marker]
-
path_to_first_node = make_path
-
first_node = find(range.first, path_to_first_node)
-
-
cur_node = first_node
-
cur_level = first_node.top_level
-
while next_node_at_level_inside_range?(cur_node, cur_level, range)
-
while can_ascend_from?(cur_node, cur_level) && next_node_at_level_inside_range?(cur_node, cur_level + 1, range)
-
cur_level += 1
-
end
-
cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker)
-
end
-
-
while node_inside_range?(cur_node, range)
-
while can_descend_from?(cur_level) && next_node_at_level_outside_range?(cur_node, cur_level, range)
-
cur_level -= 1
-
end
-
cur_node = unmark_forward_path_at_level(cur_node, cur_level, marker)
-
end
-
last_node = cur_node
-
-
first_node.endpoint_of.delete(marker)
-
if first_node.endpoint_of.empty?
-
first_node.delete(path_to_first_node)
-
end
-
-
last_node.endpoint_of.delete(marker)
-
if last_node.endpoint_of.empty?
-
path_to_last_node = make_path
-
find(range.last, path_to_last_node)
-
last_node.delete(path_to_last_node)
-
end
-
end
-
-
1
protected
-
1
attr_reader :head, :ranges
-
-
1
def insert_node(key)
-
path = make_path
-
found_node = find(key, path)
-
if found_node && found_node.key == key
-
return found_node
-
else
-
return Node.new(key, next_node_height, path)
-
end
-
end
-
-
1
def containing_with_node(n)
-
containing = []
-
cur_node = head
-
(max_height - 1).downto(0) do |cur_level|
-
while (next_node = cur_node.forward[cur_level]) && next_node.key <= n
-
cur_node = next_node
-
if cur_node.key == n
-
return containing + (cur_node.markers - cur_node.endpoint_of), cur_node
-
end
-
end
-
containing.concat(cur_node.forward_markers[cur_level])
-
end
-
-
return containing, cur_node
-
end
-
-
1
def delete_node(key)
-
path = make_path
-
found_node = find(key, path)
-
found_node.delete(path) if found_node.key == key
-
end
-
-
1
def find(key, path)
-
cur_node = head
-
(max_height - 1).downto(0) do |cur_level|
-
while (next_node = cur_node.forward[cur_level]) && next_node.key < key
-
cur_node = next_node
-
end
-
path[cur_level] = cur_node
-
end
-
cur_node.forward[0]
-
end
-
-
1
def make_path
-
Array.new(max_height, nil)
-
end
-
-
1
def next_node_height
-
height = 1
-
while rand < probability && height < max_height
-
height += 1
-
end
-
height
-
end
-
-
1
def can_ascend_from?(node, level)
-
level < node.top_level
-
end
-
-
1
def can_descend_from?(level)
-
level > 0
-
end
-
-
1
def node_inside_range?(node, range)
-
node.key < range.last
-
end
-
-
1
def next_node_at_level_inside_range?(node, level, range)
-
node.forward[level] && node.forward[level].key <= range.last
-
end
-
-
1
def next_node_at_level_outside_range?(node, level, range)
-
(node.forward[level].nil? || node.forward[level].key > range.last)
-
end
-
-
1
def mark_forward_path_at_level(node, level, marker)
-
node.forward_markers[level].push(marker)
-
next_node = node.forward[level]
-
next_node.markers.push(marker)
-
node = next_node
-
end
-
-
1
def unmark_forward_path_at_level(node, level, marker)
-
node.forward_markers[level].delete(marker)
-
next_node = node.forward[level]
-
next_node.markers.delete(marker)
-
node = next_node
-
end
-
-
1
def nodes
-
nodes = []
-
cur_node = head.forward[0]
-
until cur_node.nil?
-
nodes << cur_node
-
cur_node = cur_node.forward[0]
-
end
-
nodes
-
end
-
end
-
1
class IntervalSkipList
-
1
class Node < HeadNode
-
1
attr_accessor :key
-
1
attr_reader :markers, :endpoint_of
-
-
1
def initialize(key, height, path)
-
super(height)
-
@key = key
-
@markers = []
-
@endpoint_of = []
-
update_forward_pointers(path)
-
promote_markers(path)
-
end
-
-
1
def all_forward_markers
-
markers.flatten
-
end
-
-
1
def delete(path)
-
0.upto(top_level) do |i|
-
path[i].forward[i] = forward[i]
-
end
-
demote_markers(path)
-
end
-
-
1
def propagate_length_change(length_change)
-
cur_node = self
-
while cur_node do
-
cur_node.key += length_change
-
cur_node = cur_node.forward[0]
-
end
-
end
-
-
1
protected
-
-
1
def update_forward_pointers(path)
-
0.upto(top_level) do |i|
-
forward[i] = path[i].forward[i]
-
path[i].forward[i] = self
-
end
-
end
-
-
1
def promote_markers(path)
-
promoted = []
-
new_promoted = []
-
0.upto(top_level) do |i|
-
incoming_markers = path[i].forward_markers[i]
-
markers.concat(incoming_markers)
-
-
incoming_markers.each do |marker|
-
if can_be_promoted_higher?(marker, i)
-
new_promoted.push(marker)
-
forward[i].delete_marker_from_path(marker, i, forward[i+1])
-
else
-
forward_markers[i].push(marker)
-
end
-
end
-
-
promoted.each do |marker|
-
if can_be_promoted_higher?(marker, i)
-
new_promoted.push(marker)
-
forward[i].delete_marker_from_path(marker, i, forward[i+1])
-
else
-
forward_markers[i].push(marker)
-
end
-
end
-
-
promoted = new_promoted
-
new_promoted = []
-
end
-
end
-
-
-
1
def can_be_promoted_higher?(marker, level)
-
level < top_level && forward[level + 1] && forward[level + 1].markers.include?(marker)
-
end
-
-
1
def delete_marker_from_path(marker, level, terminus)
-
cur_node = self
-
until cur_node == terminus
-
cur_node.forward_markers[level].delete(marker)
-
cur_node.markers.delete(marker)
-
cur_node = cur_node.forward[level]
-
end
-
end
-
-
1
def demote_markers(path)
-
demote_inbound_markers(path)
-
demote_outbound_markers(path)
-
end
-
-
1
def demote_inbound_markers(path)
-
demoted = []
-
new_demoted = []
-
-
top_level.downto(0) do |i|
-
incoming_markers = path[i].forward_markers[i].dup
-
incoming_markers.each do |marker|
-
unless forward_node_with_marker_at_or_above_level?(marker, i)
-
path[i].forward_markers[i].delete(marker)
-
new_demoted.push(marker)
-
end
-
end
-
-
demoted.each do |marker|
-
path[i + 1].place_marker_on_inbound_path(marker, i, path[i])
-
-
if forward[i].markers.include?(marker)
-
path[i].forward_markers[i].push(marker)
-
else
-
new_demoted.push(marker)
-
end
-
end
-
-
demoted = new_demoted
-
new_demoted = []
-
end
-
end
-
-
1
def demote_outbound_markers(path)
-
demoted = []
-
new_demoted = []
-
-
top_level.downto(0) do |i|
-
forward_markers[i].each do |marker|
-
new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker)
-
end
-
-
demoted.each do |marker|
-
forward[i].place_marker_on_outbound_path(marker, i, forward[i + 1])
-
new_demoted.push(marker) unless path[i].forward_markers[i].include?(marker)
-
end
-
-
demoted = new_demoted
-
new_demoted = []
-
end
-
end
-
-
1
def forward_node_with_marker_at_or_above_level?(marker, level)
-
level.upto(top_level) do |i|
-
return true if forward[i].markers.include?(marker)
-
end
-
false
-
end
-
-
1
def place_marker_on_outbound_path(marker, level, terminus)
-
cur_node = self
-
until cur_node == terminus
-
cur_node.forward_markers[level].push(marker)
-
cur_node.markers.push(marker)
-
cur_node = cur_node.forward[level]
-
end
-
end
-
-
1
def place_marker_on_inbound_path(marker, level, terminus)
-
cur_node = self
-
until cur_node == terminus
-
cur_node.forward_markers[level].push(marker)
-
cur_node = cur_node.forward[level]
-
cur_node.markers.push(marker)
-
end
-
end
-
end
-
end
-
1
module Treetop
-
1
module Runtime
-
1
class SyntaxNode
-
1
attr_reader :input, :interval
-
1
attr_accessor :parent
-
-
1
def initialize(input, interval, elements = nil)
-
766
@input = input
-
766
@interval = interval
-
766
@elements = elements
-
end
-
-
1
def elements
-
312
return @elements if terminal?
-
# replace the character class placeholders in the sequence (lazy instantiation)
-
232
last_element = nil
-
@comprehensive_elements ||= @elements.map do |element|
-
168
if element == true
-
index = last_element ? last_element.interval.last : interval.first
-
element = SyntaxNode.new(input, index...(index + 1))
-
end
-
168
element.parent = self
-
168
last_element = element
-
232
end
-
-
232
@comprehensive_elements
-
end
-
-
1
def terminal?
-
312
@elements.nil?
-
end
-
-
1
def nonterminal?
-
!terminal?
-
end
-
-
1
def text_value
-
30
input[interval]
-
end
-
-
1
def empty?
-
8
interval.first == interval.last && interval.exclude_end?
-
end
-
-
1
def <=>(other)
-
self.interval.first <=> other.interval.first
-
end
-
-
1
def extension_modules
-
local_extensions =
-
class <<self
-
included_modules-Object.included_modules
-
end
-
if local_extensions.size > 0
-
local_extensions
-
else
-
[] # There weren't any; must be a literal node
-
end
-
end
-
-
1
def inspect(indent="")
-
em = extension_modules
-
interesting_methods = methods-[em.last ? em.last.methods : nil]-self.class.instance_methods
-
im = interesting_methods.size > 0 ? " (#{interesting_methods.join(",")})" : ""
-
tv = text_value
-
tv = "...#{tv[-20..-1]}" if tv.size > 20
-
-
indent +
-
self.class.to_s.sub(/.*:/,'') +
-
em.map{|m| "+"+m.to_s.sub(/.*:/,'')}*"" +
-
" offset=#{interval.first}" +
-
", #{tv.inspect}" +
-
im +
-
(elements && elements.size > 0 ?
-
":" +
-
(elements||[]).map{|e|
-
begin
-
"\n"+e.inspect(indent+" ")
-
rescue # Defend against inspect not taking a parameter
-
"\n"+indent+" "+e.inspect
-
end
-
}.join("") :
-
""
-
)
-
end
-
-
1
@@dot_id_counter = 0
-
-
1
def dot_id
-
@dot_id ||= @@dot_id_counter += 1
-
end
-
-
1
def write_dot(io)
-
io.puts "node#{dot_id} [label=\"'#{text_value}'\"];"
-
if nonterminal? then
-
elements.each do
-
|x|
-
io.puts "node#{dot_id} -> node#{x.dot_id};"
-
x.write_dot(io)
-
end
-
end
-
end
-
-
1
def write_dot_file(fname)
-
File.open(fname + ".dot","w") do
-
|file|
-
file.puts "digraph G {"
-
write_dot(file)
-
file.puts "}"
-
end
-
end
-
end
-
end
-
end
-
1
module Treetop
-
1
module Runtime
-
1
class TerminalParseFailure
-
1
attr_reader :index, :expected_string
-
-
1
def initialize(index, expected_string)
-
@index = index
-
@expected_string = expected_string
-
end
-
-
1
def to_s
-
"String matching #{expected_string} expected."
-
end
-
end
-
end
-
end
-
# encoding: UTF-8
-
-
1
module TZInfo
-
1
module Definitions
-
1
module Etc
-
1
module UTC
-
1
include TimezoneDefinition
-
-
1
timezone 'Etc/UTC' do |tz|
-
1
tz.offset :o0, 0, 0, :UTC
-
-
end
-
end
-
end
-
end
-
end